VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win/SUPSvc-win.cpp@ 92270

Last change on this file since 92270 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.3 KB
Line 
1/* $Id: SUPSvc-win.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * VirtualBox Support Service - Windows Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008-2020 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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP LOG_GROUP_SUP
32#include <iprt/win/windows.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#ifdef DEBUG_bird
43# include <iprt/env.h>
44#endif
45
46#include "../SUPSvcInternal.h"
47
48
49/*********************************************************************************************************************************
50* Defined Constants And Macros *
51*********************************************************************************************************************************/
52/** The service name. */
53#define SUPSVC_SERVICE_NAME "VBoxSupSvc"
54/** The service display name. */
55#define SUPSVC_SERVICE_DISPLAY_NAME "VirtualBox Support Service"
56
57
58/*********************************************************************************************************************************
59* Global Variables *
60*********************************************************************************************************************************/
61/** The service control handler handle. */
62static SERVICE_STATUS_HANDLE g_hSupSvcWinCtrlHandler = NULL;
63/** The service status. */
64static uint32_t volatile g_u32SupSvcWinStatus = SERVICE_STOPPED;
65/** The semaphore the main service thread is waiting on in supSvcWinServiceMain. */
66static RTSEMEVENTMULTI g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
67
68
69/*********************************************************************************************************************************
70* Internal Functions *
71*********************************************************************************************************************************/
72static SC_HANDLE supSvcWinOpenSCManager(const char *pszAction, DWORD dwAccess);
73
74
75/**
76 * Opens the service control manager.
77 *
78 * When this fails, an error message will be displayed.
79 *
80 * @returns Valid handle on success.
81 * NULL on failure, will display an error message.
82 *
83 * @param pszAction The action which is requesting access to SCM.
84 * @param dwAccess The desired access.
85 */
86static SC_HANDLE supSvcWinOpenSCManager(const char *pszAction, DWORD dwAccess)
87{
88 SC_HANDLE hSCM = OpenSCManager(NULL /* lpMachineName*/, NULL /* lpDatabaseName */, dwAccess);
89 if (hSCM == NULL)
90 {
91 DWORD err = GetLastError();
92 switch (err)
93 {
94 case ERROR_ACCESS_DENIED:
95 supSvcDisplayError("%s - OpenSCManager failure: access denied\n", pszAction);
96 break;
97 default:
98 supSvcDisplayError("%s - OpenSCManager failure: %d\n", pszAction, err);
99 break;
100 }
101 }
102 return hSCM;
103}
104
105
106/**
107 * Opens the service.
108 *
109 * Last error is preserved on failure and set to 0 on success.
110 *
111 * @returns Valid service handle on success.
112 * NULL on failure, will display an error message unless it's ignored.
113 *
114 * @param pszAction The action which is requesting access to the service.
115 * @param dwSCMAccess The service control manager access.
116 * @param dwSVCAccess The desired service access.
117 * @param cIgnoredErrors The number of ignored errors.
118 * @param ... Errors codes that should not cause a message to be displayed.
119 */
120static SC_HANDLE supSvcWinOpenService(const char *pszAction, DWORD dwSCMAccess, DWORD dwSVCAccess,
121 unsigned cIgnoredErrors, ...)
122{
123 SC_HANDLE hSCM = supSvcWinOpenSCManager(pszAction, dwSCMAccess);
124 if (!hSCM)
125 return NULL;
126
127 SC_HANDLE hSvc = OpenService(hSCM, SUPSVC_SERVICE_NAME, dwSVCAccess);
128 if (hSvc)
129 {
130 CloseServiceHandle(hSCM);
131 SetLastError(0);
132 }
133 else
134 {
135 DWORD err = GetLastError();
136 bool fIgnored = false;
137 va_list va;
138 va_start(va, cIgnoredErrors);
139 while (!fIgnored && cIgnoredErrors-- > 0)
140 fIgnored = va_arg(va, long) == err;
141 va_end(va);
142 if (!fIgnored)
143 {
144 switch (err)
145 {
146 case ERROR_ACCESS_DENIED:
147 supSvcDisplayError("%s - OpenService failure: access denied\n", pszAction);
148 break;
149 case ERROR_SERVICE_DOES_NOT_EXIST:
150 supSvcDisplayError("%s - OpenService failure: The service does not exist. Reinstall it.\n", pszAction);
151 break;
152 default:
153 supSvcDisplayError("%s - OpenService failure: %d\n", pszAction, err);
154 break;
155 }
156 }
157
158 CloseServiceHandle(hSCM);
159 SetLastError(err);
160 }
161 return hSvc;
162}
163
164
165
166void supSvcOsLogErrorStr(const char *pszMsg)
167{
168 HANDLE hEventLog = RegisterEventSource(NULL /* local computer */, "VBoxSupSvc");
169 AssertReturnVoid(hEventLog != NULL);
170 const char *apsz[2];
171 apsz[0] = "VBoxSupSvc";
172 apsz[1] = pszMsg;
173 BOOL fRc = ReportEvent(hEventLog, /* hEventLog */
174 EVENTLOG_ERROR_TYPE, /* wType */
175 0, /* wCategory */
176 0 /** @todo mc */, /* dwEventID */
177 NULL, /* lpUserSid */
178 RT_ELEMENTS(apsz), /* wNumStrings */
179 0, /* dwDataSize */
180 apsz, /* lpStrings */
181 NULL); /* lpRawData */
182 AssertMsg(fRc, ("%d\n", GetLastError()));
183 DeregisterEventSource(hEventLog);
184}
185
186
187static int supSvcWinInterrogate(int argc, char **argv)
188{
189 RTPrintf("VBoxSupSvc: The \"interrogate\" action is not implemented.\n");
190 return 1;
191}
192
193
194static int supSvcWinStop(int argc, char **argv)
195{
196 RTPrintf("VBoxSupSvc: The \"stop\" action is not implemented.\n");
197 return 1;
198}
199
200
201static int supSvcWinContinue(int argc, char **argv)
202{
203 RTPrintf("VBoxSupSvc: The \"continue\" action is not implemented.\n");
204 return 1;
205}
206
207
208static int supSvcWinPause(int argc, char **argv)
209{
210 RTPrintf("VBoxSupSvc: The \"pause\" action is not implemented.\n");
211 return 1;
212}
213
214
215static int supSvcWinStart(int argc, char **argv)
216{
217 RTPrintf("VBoxSupSvc: The \"start\" action is not implemented.\n");
218 return 1;
219}
220
221
222static int supSvcWinQueryDescription(int argc, char **argv)
223{
224 RTPrintf("VBoxSupSvc: The \"qdescription\" action is not implemented.\n");
225 return 1;
226}
227
228
229static int supSvcWinQueryConfig(int argc, char **argv)
230{
231 RTPrintf("VBoxSupSvc: The \"qconfig\" action is not implemented.\n");
232 return 1;
233}
234
235
236static int supSvcWinDisable(int argc, char **argv)
237{
238 RTPrintf("VBoxSupSvc: The \"disable\" action is not implemented.\n");
239 return 1;
240}
241
242static int supSvcWinEnable(int argc, char **argv)
243{
244 RTPrintf("VBoxSupSvc: The \"enable\" action is not implemented.\n");
245 return 1;
246}
247
248
249/**
250 * Handle the 'delete' action.
251 *
252 * @returns 0 or 1.
253 * @param argc The action argument count.
254 * @param argv The action argument vector.
255 */
256static int supSvcWinDelete(int argc, char **argv)
257{
258 /*
259 * Parse the arguments.
260 */
261 bool fVerbose = false;
262 static const RTGETOPTDEF s_aOptions[] =
263 {
264 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
265 };
266 int ch;
267 RTGETOPTUNION Value;
268 RTGETOPTSTATE GetState;
269 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
270 while ((ch = RTGetOpt(&GetState, &Value)))
271 switch (ch)
272 {
273 case 'v':
274 fVerbose = true;
275 break;
276 case VINF_GETOPT_NOT_OPTION:
277 return supSvcDisplayTooManyArgsError("delete", argc, argv, iArg);
278 default:
279 return supSvcDisplayGetOptError("delete", ch, argc, argv, iArg, &Value);
280 }
281
282 /*
283 * Create the service.
284 */
285 int rc = 1;
286 SC_HANDLE hSvc = supSvcWinOpenService("delete", SERVICE_CHANGE_CONFIG, DELETE,
287 1, ERROR_SERVICE_DOES_NOT_EXIST);
288 if (hSvc)
289 {
290 if (DeleteService(hSvc))
291 {
292 RTPrintf("Successfully deleted the %s service.\n", SUPSVC_SERVICE_NAME);
293 rc = 0;
294 }
295 else
296 supSvcDisplayError("delete - DeleteService failed, err=%d.\n", GetLastError());
297 CloseServiceHandle(hSvc);
298 }
299 else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
300 {
301
302 if (fVerbose)
303 RTPrintf("The service %s was not installed, nothing to be done.", SUPSVC_SERVICE_NAME);
304 else
305 RTPrintf("Successfully deleted the %s service.\n", SUPSVC_SERVICE_NAME);
306 rc = 0;
307 }
308 return rc;
309}
310
311
312/**
313 * Handle the 'create' action.
314 *
315 * @returns 0 or 1.
316 * @param argc The action argument count.
317 * @param argv The action argument vector.
318 */
319static int supSvcWinCreate(int argc, char **argv)
320{
321 /*
322 * Parse the arguments.
323 */
324 bool fVerbose = false;
325 static const RTOPTIONDEF s_aOptions[] =
326 {
327 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
328 };
329 int iArg = 0;
330 int ch;
331 RTGETOPTUNION Value;
332 while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
333 switch (ch)
334 {
335 case 'v': fVerbose = true; break;
336 default: return supSvcDisplayGetOptError("create", ch, argc, argv, iArg, &Value);
337 }
338 if (iArg != argc)
339 return supSvcDisplayTooManyArgsError("create", argc, argv, iArg);
340
341 /*
342 * Create the service.
343 */
344 int rc = 1;
345 SC_HANDLE hSCM = supSvcWinOpenSCManager("create", SC_MANAGER_CREATE_SERVICE); /*SC_MANAGER_ALL_ACCESS*/
346 if (hSCM)
347 {
348 char szExecPath[MAX_PATH];
349 if (GetModuleFileName(NULL /* the executable */, szExecPath, sizeof(szExecPath)))
350 {
351 if (fVerbose)
352 RTPrintf("Creating the %s service, binary \"%s\"...\n",
353 SUPSVC_SERVICE_NAME, szExecPath); /* yea, the binary name isn't UTF-8, but wtf. */
354
355 SC_HANDLE hSvc = CreateService(hSCM, /* hSCManager */
356 SUPSVC_SERVICE_NAME, /* lpServiceName */
357 SUPSVC_SERVICE_DISPLAY_NAME, /* lpDisplayName */
358 SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG, /* dwDesiredAccess */
359 SERVICE_WIN32_OWN_PROCESS, /* dwServiceType ( | SERVICE_INTERACTIVE_PROCESS? ) */
360 SERVICE_DEMAND_START/*_AUTO*/, /* dwStartType */
361 SERVICE_ERROR_NORMAL, /* dwErrorControl */
362 szExecPath, /* lpBinaryPathName */
363 NULL, /* lpLoadOrderGroup */
364 NULL, /* lpdwTagId */
365 NULL, /* lpDependencies */
366 NULL, /* lpServiceStartName (=> LocalSystem) */
367 NULL); /* lpPassword */
368 if (hSvc)
369 {
370 RTPrintf("Successfully created the %s service.\n", SUPSVC_SERVICE_NAME);
371 /** @todo Set the service description or it'll look weird in the vista service manager.
372 * Anything else that should be configured? Start access or something? */
373 rc = 0;
374 CloseServiceHandle(hSvc);
375 }
376 else
377 {
378 DWORD err = GetLastError();
379 switch (err)
380 {
381 case ERROR_SERVICE_EXISTS:
382 supSvcDisplayError("create - The service already exists.\n");
383 break;
384 default:
385 supSvcDisplayError("create - CreateService failed, err=%d.\n", GetLastError());
386 break;
387 }
388 }
389 CloseServiceHandle(hSvc);
390 }
391 else
392 supSvcDisplayError("create - Failed to obtain the executable path: %d\n", GetLastError());
393 }
394 return rc;
395}
396
397
398/**
399 * Sets the service status, just a SetServiceStatus Wrapper.
400 *
401 * @returns See SetServiceStatus.
402 * @param dwStatus The current status.
403 * @param iWaitHint The wait hint, if < 0 then supply a default.
404 * @param dwExitCode The service exit code.
405 */
406static bool supSvcWinSetServiceStatus(DWORD dwStatus, int iWaitHint, DWORD dwExitCode)
407{
408 SERVICE_STATUS SvcStatus;
409 SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
410 SvcStatus.dwWin32ExitCode = dwExitCode;
411 SvcStatus.dwServiceSpecificExitCode = 0;
412 SvcStatus.dwWaitHint = iWaitHint >= 0 ? iWaitHint : 3000;
413 SvcStatus.dwCurrentState = dwStatus;
414 LogFlow(("supSvcWinSetServiceStatus: %d -> %d\n", g_u32SupSvcWinStatus, dwStatus));
415 g_u32SupSvcWinStatus = dwStatus;
416 switch (dwStatus)
417 {
418 case SERVICE_START_PENDING:
419 SvcStatus.dwControlsAccepted = 0;
420 break;
421 default:
422 SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
423 break;
424 }
425
426 static DWORD dwCheckPoint = 0;
427 switch (dwStatus)
428 {
429 case SERVICE_RUNNING:
430 case SERVICE_STOPPED:
431 SvcStatus.dwCheckPoint = 0;
432 default:
433 SvcStatus.dwCheckPoint = ++dwCheckPoint;
434 break;
435 }
436 return SetServiceStatus(g_hSupSvcWinCtrlHandler, &SvcStatus) != FALSE;
437}
438
439
440/**
441 * Service control handler (extended).
442 *
443 * @returns Windows status (see HandlerEx).
444 * @retval NO_ERROR if handled.
445 * @retval ERROR_CALL_NOT_IMPLEMENTED if not handled.
446 *
447 * @param dwControl The control code.
448 * @param dwEventType Event type. (specific to the control?)
449 * @param pvEventData Event data, specific to the event.
450 * @param pvContext The context pointer registered with the handler.
451 * Currently not used.
452 */
453static DWORD WINAPI supSvcWinServiceCtrlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID pvEventData, LPVOID pvContext)
454{
455 LogFlow(("supSvcWinServiceCtrlHandlerEx: dwControl=%#x dwEventType=%#x pvEventData=%p\n",
456 dwControl, dwEventType, pvEventData));
457
458 switch (dwControl)
459 {
460 /*
461 * Interrogate the service about it's current status.
462 * MSDN says that this should just return NO_ERROR and does
463 * not need to set the status again.
464 */
465 case SERVICE_CONTROL_INTERROGATE:
466 return NO_ERROR;
467
468 /*
469 * Request to stop the service.
470 */
471 case SERVICE_CONTROL_STOP:
472 {
473 /*
474 * Check if the real services can be stopped and then tell them to stop.
475 */
476 supSvcWinSetServiceStatus(SERVICE_STOP_PENDING, 3000, NO_ERROR);
477 int rc = supSvcTryStopServices();
478 if (RT_SUCCESS(rc))
479 {
480 /*
481 * Notify the main thread that we're done, it will wait for the
482 * real services to stop, destroy them, and finally set the windows
483 * service status to SERVICE_STOPPED and return.
484 */
485 rc = RTSemEventMultiSignal(g_hSupSvcWinEvent);
486 if (RT_FAILURE(rc))
487 supSvcLogError("SERVICE_CONTROL_STOP: RTSemEventMultiSignal failed, %Rrc\n", rc);
488 }
489 return NO_ERROR;
490 }
491
492 case SERVICE_CONTROL_PAUSE:
493 case SERVICE_CONTROL_CONTINUE:
494 case SERVICE_CONTROL_SHUTDOWN:
495 case SERVICE_CONTROL_PARAMCHANGE:
496 case SERVICE_CONTROL_NETBINDADD:
497 case SERVICE_CONTROL_NETBINDREMOVE:
498 case SERVICE_CONTROL_NETBINDENABLE:
499 case SERVICE_CONTROL_NETBINDDISABLE:
500 case SERVICE_CONTROL_DEVICEEVENT:
501 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
502 case SERVICE_CONTROL_POWEREVENT:
503 case SERVICE_CONTROL_SESSIONCHANGE:
504#ifdef SERVICE_CONTROL_PRESHUTDOWN /* vista */
505 case SERVICE_CONTROL_PRESHUTDOWN:
506#endif
507 default:
508 return ERROR_CALL_NOT_IMPLEMENTED;
509 }
510
511 NOREF(dwEventType);
512 NOREF(pvEventData);
513 NOREF(pvContext);
514 return NO_ERROR;
515}
516
517
518/**
519 * Windows Service Main.
520 *
521 * This is invoked when the service is started and should not return until
522 * the service has been stopped.
523 *
524 * @param cArgs Argument count.
525 * @param papszArgs Argument vector.
526 */
527static VOID WINAPI supSvcWinServiceMain(DWORD cArgs, LPSTR *papszArgs)
528{
529 LogFlowFuncEnter();
530
531 /*
532 * Register the control handler function for the service and report to SCM.
533 */
534 Assert(g_u32SupSvcWinStatus == SERVICE_STOPPED);
535 g_hSupSvcWinCtrlHandler = RegisterServiceCtrlHandlerEx(SUPSVC_SERVICE_NAME, supSvcWinServiceCtrlHandlerEx, NULL);
536 if (g_hSupSvcWinCtrlHandler)
537 {
538 DWORD err = ERROR_GEN_FAILURE;
539 if (supSvcWinSetServiceStatus(SERVICE_START_PENDING, 3000, NO_ERROR))
540 {
541 /*
542 * Parse arguments.
543 */
544 static const RTOPTIONDEF s_aOptions[] =
545 {
546 { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
547 };
548 int iArg = 1; /* the first arg is the service name */
549 int ch;
550 int rc = 0;
551 RTGETOPTUNION Value;
552 while ( !rc
553 && (ch = RTGetOpt(cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
554 switch (ch)
555 {
556 default: rc = supSvcLogGetOptError("main", ch, cArgs, papszArgs, iArg, &Value); break;
557 }
558 if (iArg != cArgs)
559 rc = supSvcLogTooManyArgsError("main", cArgs, papszArgs, iArg);
560 if (!rc)
561 {
562 /*
563 * Create the event semaphore we'll be waiting on and
564 * then instantiate the actual services.
565 */
566 int rc = RTSemEventMultiCreate(&g_hSupSvcWinEvent);
567 if (RT_SUCCESS(rc))
568 {
569 rc = supSvcCreateAndStartServices();
570 if (RT_SUCCESS(rc))
571 {
572 /*
573 * Update the status and enter the work loop.
574 *
575 * The work loop is just a dummy wait here as the services run
576 * in independent threads.
577 */
578 if (supSvcWinSetServiceStatus(SERVICE_RUNNING, 0, 0))
579 {
580 LogFlow(("supSvcWinServiceMain: calling RTSemEventMultiWait\n"));
581 rc = RTSemEventMultiWait(g_hSupSvcWinEvent, RT_INDEFINITE_WAIT);
582 if (RT_SUCCESS(rc))
583 {
584 LogFlow(("supSvcWinServiceMain: woke up\n"));
585 err = NO_ERROR;
586 }
587 else
588 supSvcLogError("RTSemEventWait failed, rc=%Rrc", rc);
589 }
590 else
591 {
592 err = GetLastError();
593 supSvcLogError("SetServiceStatus failed, err=%d", err);
594 }
595
596 /*
597 * Destroy the service instances, stopping them if
598 * they're still running (weird failure cause).
599 */
600 supSvcStopAndDestroyServices();
601 }
602
603 RTSemEventMultiDestroy(g_hSupSvcWinEvent);
604 g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
605 }
606 else
607 supSvcLogError("RTSemEventMultiCreate failed, rc=%Rrc", rc);
608 }
609 /* else: bad args */
610 }
611 else
612 {
613 err = GetLastError();
614 supSvcLogError("SetServiceStatus failed, err=%d", err);
615 }
616 supSvcWinSetServiceStatus(SERVICE_STOPPED, 0, err);
617 }
618 else
619 supSvcLogError("RegisterServiceCtrlHandlerEx failed, err=%d", GetLastError());
620 LogFlowFuncLeave();
621}
622
623
624/**
625 * Handle the 'create' action.
626 *
627 * @returns 0 or 1.
628 * @param argc The action argument count.
629 * @param argv The action argument vector.
630 */
631static int supSvcWinRunIt(int argc, char **argv)
632{
633 LogFlowFuncEnter();
634
635 /*
636 * Initialize release logging.
637 */
638 /** @todo release logging of the system-wide service. */
639
640 /*
641 * Parse the arguments.
642 */
643 static const RTOPTIONDEF s_aOptions[] =
644 {
645 { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
646 };
647 int iArg = 0;
648 int ch;
649 RTGETOPTUNION Value;
650 while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
651 switch (ch)
652 {
653 default: return supSvcDisplayGetOptError("runit", ch, argc, argv, iArg, &Value);
654 }
655 if (iArg != argc)
656 return supSvcDisplayTooManyArgsError("runit", argc, argv, iArg);
657
658 /*
659 * Register the service with the service control manager
660 * and start dispatching requests from it (all done by the API).
661 */
662 static SERVICE_TABLE_ENTRY const s_aServiceStartTable[] =
663 {
664 { SUPSVC_SERVICE_NAME, supSvcWinServiceMain },
665 { NULL, NULL}
666 };
667 if (StartServiceCtrlDispatcher(&s_aServiceStartTable[0]))
668 {
669 LogFlowFuncLeave();
670 return 0; /* told to quit, so quit. */
671 }
672
673 DWORD err = GetLastError();
674 switch (err)
675 {
676 case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
677 supSvcDisplayError("Cannot run a service from the command line. Use the 'start' action to start it the right way.\n");
678 break;
679 default:
680 supSvcLogError("StartServiceCtrlDispatcher failed, err=%d", err);
681 break;
682 }
683 return 1;
684}
685
686
687/**
688 * Show the version info.
689 *
690 * @returns 0.
691 */
692static int supSvcWinShowVersion(int argc, char **argv)
693{
694 /*
695 * Parse the arguments.
696 */
697 bool fBrief = false;
698 static const RTOPTIONDEF s_aOptions[] =
699 {
700 { "--brief", 'b', RTGETOPT_REQ_NOTHING }
701 };
702 int iArg = 0;
703 int ch;
704 RTGETOPTUNION Value;
705 while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
706 switch (ch)
707 {
708 case 'b': fBrief = true; break;
709 default: return supSvcDisplayGetOptError("version", ch, argc, argv, iArg, &Value);
710
711 }
712 if (iArg != argc)
713 return supSvcDisplayTooManyArgsError("version", argc, argv, iArg);
714
715 /*
716 * Do the printing.
717 */
718 if (fBrief)
719 RTPrintf("%s\n", VBOX_VERSION_STRING);
720 else
721 RTPrintf("VirtualBox System Service Version %s\n"
722 "(C) 2008-2010 Oracle Corporation\n"
723 "All rights reserved.\n",
724 VBOX_VERSION_STRING);
725 return 0;
726}
727
728
729/**
730 * Show the usage help screen.
731 *
732 * @returns 0.
733 */
734static int supSvcWinShowHelp(void)
735{
736 RTPrintf("VirtualBox System Service Version %s\n"
737 "(C) 2008-2010 Oracle Corporation\n"
738 "All rights reserved.\n"
739 "\n",
740 VBOX_VERSION_STRING);
741 RTPrintf("Usage:\n"
742 "\n"
743 "VBoxSupSvc\n"
744 " Runs the service.\n"
745 "VBoxSupSvc <version|-v|--version> [-brief]\n"
746 " Displays the version.\n"
747 "VBoxSupSvc <help|-?|-h|--help> [...]\n"
748 " Displays this help screen.\n"
749 "\n"
750 "VBoxSupSvc <install|/RegServer|/i>\n"
751 " Installs the service.\n"
752 "VBoxSupSvc <install|delete|/UnregServer|/u>\n"
753 " Uninstalls the service.\n"
754 );
755 return 0;
756}
757
758
759/**
760 * VBoxSUPSvc main(), Windows edition.
761 *
762 *
763 * @returns 0 on success.
764 *
765 * @param argc Number of arguments in argv.
766 * @param argv Argument vector.
767 */
768int main(int argc, char **argv)
769{
770 /*
771 * Initialize the IPRT first of all.
772 */
773#ifdef DEBUG_bird
774 RTEnvSet("VBOX_LOG", "sup=~0");
775 RTEnvSet("VBOX_LOG_DEST", "file=E:\\temp\\VBoxSupSvc.log");
776 RTEnvSet("VBOX_LOG_FLAGS", "unbuffered thread msprog");
777#endif
778 int rc = RTR3InitExe(argc, &argv, 0);
779 if (RT_FAILURE(rc))
780 {
781 supSvcLogError("RTR3InitExe failed with rc=%Rrc", rc);
782 return 1;
783 }
784
785 /*
786 * Parse the initial arguments to determine the desired action.
787 */
788 enum
789 {
790 kSupSvcAction_RunIt,
791
792 kSupSvcAction_Create,
793 kSupSvcAction_Delete,
794
795 kSupSvcAction_Enable,
796 kSupSvcAction_Disable,
797 kSupSvcAction_QueryConfig,
798 kSupSvcAction_QueryDescription,
799
800 kSupSvcAction_Start,
801 kSupSvcAction_Pause,
802 kSupSvcAction_Continue,
803 kSupSvcAction_Stop,
804 kSupSvcAction_Interrogate,
805
806 kSupSvcAction_End
807 } enmAction = kSupSvcAction_RunIt;
808 int iArg = 1;
809 if (argc > 1)
810 {
811 if ( !stricmp(argv[iArg], "/RegServer")
812 || !stricmp(argv[iArg], "install")
813 || !stricmp(argv[iArg], "/i"))
814 enmAction = kSupSvcAction_Create;
815 else if ( !stricmp(argv[iArg], "/UnregServer")
816 || !stricmp(argv[iArg], "/u")
817 || !stricmp(argv[iArg], "uninstall")
818 || !stricmp(argv[iArg], "delete"))
819 enmAction = kSupSvcAction_Delete;
820
821 else if (!stricmp(argv[iArg], "enable"))
822 enmAction = kSupSvcAction_Enable;
823 else if (!stricmp(argv[iArg], "disable"))
824 enmAction = kSupSvcAction_Disable;
825 else if (!stricmp(argv[iArg], "qconfig"))
826 enmAction = kSupSvcAction_QueryConfig;
827 else if (!stricmp(argv[iArg], "qdescription"))
828 enmAction = kSupSvcAction_QueryDescription;
829
830 else if ( !stricmp(argv[iArg], "start")
831 || !stricmp(argv[iArg], "/t"))
832 enmAction = kSupSvcAction_Start;
833 else if (!stricmp(argv[iArg], "pause"))
834 enmAction = kSupSvcAction_Start;
835 else if (!stricmp(argv[iArg], "continue"))
836 enmAction = kSupSvcAction_Continue;
837 else if (!stricmp(argv[iArg], "stop"))
838 enmAction = kSupSvcAction_Stop;
839 else if (!stricmp(argv[iArg], "interrogate"))
840 enmAction = kSupSvcAction_Interrogate;
841 else if ( !stricmp(argv[iArg], "help")
842 || !stricmp(argv[iArg], "?")
843 || !stricmp(argv[iArg], "/?")
844 || !stricmp(argv[iArg], "-?")
845 || !stricmp(argv[iArg], "/h")
846 || !stricmp(argv[iArg], "-h")
847 || !stricmp(argv[iArg], "/help")
848 || !stricmp(argv[iArg], "-help")
849 || !stricmp(argv[iArg], "--help"))
850 return supSvcWinShowHelp();
851 else if ( !stricmp(argv[iArg], "version")
852 || !stricmp(argv[iArg], "/v")
853 || !stricmp(argv[iArg], "-v")
854 || !stricmp(argv[iArg], "/version")
855 || !stricmp(argv[iArg], "-version")
856 || !stricmp(argv[iArg], "--version"))
857 return supSvcWinShowVersion(argc - iArg - 1, argv + iArg + 1);
858 else
859 iArg--;
860 iArg++;
861 }
862
863 /*
864 * Dispatch it.
865 */
866 switch (enmAction)
867 {
868 case kSupSvcAction_RunIt:
869 return supSvcWinRunIt(argc - iArg, argv + iArg);
870
871 case kSupSvcAction_Create:
872 return supSvcWinCreate(argc - iArg, argv + iArg);
873 case kSupSvcAction_Delete:
874 return supSvcWinDelete(argc - iArg, argv + iArg);
875
876 case kSupSvcAction_Enable:
877 return supSvcWinEnable(argc - iArg, argv + iArg);
878 case kSupSvcAction_Disable:
879 return supSvcWinDisable(argc - iArg, argv + iArg);
880 case kSupSvcAction_QueryConfig:
881 return supSvcWinQueryConfig(argc - iArg, argv + iArg);
882 case kSupSvcAction_QueryDescription:
883 return supSvcWinQueryDescription(argc - iArg, argv + iArg);
884
885 case kSupSvcAction_Start:
886 return supSvcWinStart(argc - iArg, argv + iArg);
887 case kSupSvcAction_Pause:
888 return supSvcWinPause(argc - iArg, argv + iArg);
889 case kSupSvcAction_Continue:
890 return supSvcWinContinue(argc - iArg, argv + iArg);
891 case kSupSvcAction_Stop:
892 return supSvcWinStop(argc - iArg, argv + iArg);
893 case kSupSvcAction_Interrogate:
894 return supSvcWinInterrogate(argc - iArg, argv + iArg);
895
896 default:
897 AssertMsgFailed(("enmAction=%d\n", enmAction));
898 return 1;
899 }
900}
901
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