VirtualBox

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

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