VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxService.cpp@ 33294

Last change on this file since 33294 was 33277, checked in by vboxsync, 14 years ago

VBoxService: Update on internal toolbox command handling.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.3 KB
Line 
1/* $Id: VBoxService.cpp 33277 2010-10-20 20:09:05Z vboxsync $ */
2/** @file
3 * VBoxService - Guest Additions Service Skeleton.
4 */
5
6/*
7 * Copyright (C) 2007-2010 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/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23/** @todo LOG_GROUP*/
24#ifndef _MSC_VER
25# include <unistd.h>
26#endif
27#include <errno.h>
28#ifndef RT_OS_WINDOWS
29# include <signal.h>
30#endif
31#ifdef RT_OS_FREEBSD
32# include <pthread.h>
33#endif
34
35#include "product-generated.h"
36#include <iprt/asm.h>
37#include <iprt/buildconfig.h>
38#include <iprt/initterm.h>
39#include <iprt/path.h>
40#include <iprt/semaphore.h>
41#include <iprt/string.h>
42#include <iprt/stream.h>
43#include <iprt/thread.h>
44
45#include <VBox/VBoxGuestLib.h>
46#include <VBox/log.h>
47
48#include "VBoxServiceInternal.h"
49
50
51/*******************************************************************************
52* Global Variables *
53*******************************************************************************/
54/** The program name (derived from argv[0]). */
55char *g_pszProgName = (char *)"";
56/** The current verbosity level. */
57int g_cVerbosity = 0;
58/** The default service interval (the -i | --interval) option). */
59uint32_t g_DefaultInterval = 0;
60#ifdef RT_OS_WINDOWS
61/** Signal shutdown to the Windows service thread. */
62static bool volatile g_fWindowsServiceShutdown;
63/** Event the Windows service thread waits for shutdown. */
64static RTSEMEVENT g_hEvtWindowsService;
65#endif
66
67/**
68 * The details of the services that has been compiled in.
69 */
70static struct
71{
72 /** Pointer to the service descriptor. */
73 PCVBOXSERVICE pDesc;
74 /** The worker thread. NIL_RTTHREAD if it's the main thread. */
75 RTTHREAD Thread;
76 /** Shutdown indicator. */
77 bool volatile fShutdown;
78 /** Indicator set by the service thread exiting. */
79 bool volatile fStopped;
80 /** Whether the service was started or not. */
81 bool fStarted;
82 /** Whether the service is enabled or not. */
83 bool fEnabled;
84} g_aServices[] =
85{
86#ifdef VBOXSERVICE_CONTROL
87 { &g_Control, NIL_RTTHREAD, false, false, false, true },
88#endif
89#ifdef VBOXSERVICE_TIMESYNC
90 { &g_TimeSync, NIL_RTTHREAD, false, false, false, true },
91#endif
92#ifdef VBOXSERVICE_CLIPBOARD
93 { &g_Clipboard, NIL_RTTHREAD, false, false, false, true },
94#endif
95#ifdef VBOXSERVICE_VMINFO
96 { &g_VMInfo, NIL_RTTHREAD, false, false, false, true },
97#endif
98#ifdef VBOXSERVICE_CPUHOTPLUG
99 { &g_CpuHotPlug, NIL_RTTHREAD, false, false, false, true },
100#endif
101#ifdef VBOXSERVICE_MANAGEMENT
102# ifdef VBOX_WITH_MEMBALLOON
103 { &g_MemBalloon, NIL_RTTHREAD, false, false, false, true },
104# endif
105 { &g_VMStatistics, NIL_RTTHREAD, false, false, false, true },
106#endif
107#if defined(VBOX_WITH_PAGE_SHARING) && defined(RT_OS_WINDOWS)
108 { &g_PageSharing, NIL_RTTHREAD, false, false, false, true },
109#endif
110#ifdef VBOX_WITH_SHARED_FOLDERS
111 { &g_AutoMount, NIL_RTTHREAD, false, false, false, true },
112#endif
113};
114
115
116/**
117 * Displays the program usage message.
118 *
119 * @returns 1.
120 */
121static int VBoxServiceUsage(void)
122{
123 RTPrintf("Usage:\n"
124 " %-12s [-f|--foreground] [-v|--verbose] [-i|--interval <seconds>]\n"
125 " [--disable-<service>] [--enable-<service>] [-h|-?|--help]\n", g_pszProgName);
126#ifdef RT_OS_WINDOWS
127 RTPrintf(" [-r|--register] [-u|--unregister]\n");
128#endif
129 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
130 if (g_aServices[j].pDesc->pszUsage)
131 RTPrintf("%s\n", g_aServices[j].pDesc->pszUsage);
132 RTPrintf("\n"
133 "Options:\n"
134 " -i | --interval The default interval.\n"
135 " -f | --foreground Don't daemonzie the program. For debugging.\n"
136 " -v | --verbose Increment the verbosity level. For debugging.\n"
137 " -h | -? | --help Show this message and exit with status 1.\n"
138 );
139#ifdef RT_OS_WINDOWS
140 RTPrintf(" -r | --register Installs the service.\n"
141 " -u | --unregister Uninstall service.\n");
142#endif
143
144 RTPrintf("\n"
145 "Service-specific options:\n");
146 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
147 {
148 RTPrintf(" --enable-%-14s Enables the %s service. (default)\n", g_aServices[j].pDesc->pszName, g_aServices[j].pDesc->pszName);
149 RTPrintf(" --disable-%-13s Disables the %s service.\n", g_aServices[j].pDesc->pszName, g_aServices[j].pDesc->pszName);
150 if (g_aServices[j].pDesc->pszOptions)
151 RTPrintf("%s", g_aServices[j].pDesc->pszOptions);
152 }
153 RTPrintf("\n"
154 " Copyright (C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n");
155
156 return 1;
157}
158
159
160/**
161 * Displays a syntax error message.
162 *
163 * @returns RTEXITCODE_SYNTAX.
164 * @param pszFormat The message text.
165 * @param ... Format arguments.
166 */
167RTEXITCODE VBoxServiceSyntax(const char *pszFormat, ...)
168{
169 RTStrmPrintf(g_pStdErr, "%s: syntax error: ", g_pszProgName);
170
171 va_list va;
172 va_start(va, pszFormat);
173 RTStrmPrintfV(g_pStdErr, pszFormat, va);
174 va_end(va);
175
176 return RTEXITCODE_SYNTAX;
177}
178
179
180/**
181 * Displays an error message.
182 *
183 * @returns RTEXITCODE_FAILURE.
184 * @param pszFormat The message text.
185 * @param ... Format arguments.
186 */
187RTEXITCODE VBoxServiceError(const char *pszFormat, ...)
188{
189 RTStrmPrintf(g_pStdErr, "%s: error: ", g_pszProgName);
190
191 va_list va;
192 va_start(va, pszFormat);
193 RTStrmPrintfV(g_pStdErr, pszFormat, va);
194 va_end(va);
195
196 va_start(va, pszFormat);
197 LogRel(("%s: Error: %N", g_pszProgName, pszFormat, &va));
198 va_end(va);
199
200 return RTEXITCODE_FAILURE;
201}
202
203
204/**
205 * Displays a verbose message.
206 *
207 * @returns 1
208 * @param pszFormat The message text.
209 * @param ... Format arguments.
210 */
211void VBoxServiceVerbose(int iLevel, const char *pszFormat, ...)
212{
213 if (iLevel <= g_cVerbosity)
214 {
215 RTStrmPrintf(g_pStdOut, "%s: ", g_pszProgName);
216 va_list va;
217 va_start(va, pszFormat);
218 RTStrmPrintfV(g_pStdOut, pszFormat, va);
219 va_end(va);
220 va_start(va, pszFormat);
221 LogRel(("%s: %N", g_pszProgName, pszFormat, &va));
222 va_end(va);
223 }
224}
225
226
227/**
228 * Gets a 32-bit value argument.
229 *
230 * @returns 0 on success, non-zero exit code on error.
231 * @param argc The argument count.
232 * @param argv The argument vector
233 * @param psz Where in *pi to start looking for the value argument.
234 * @param pi Where to find and perhaps update the argument index.
235 * @param pu32 Where to store the 32-bit value.
236 * @param u32Min The minimum value.
237 * @param u32Max The maximum value.
238 */
239int VBoxServiceArgUInt32(int argc, char **argv, const char *psz, int *pi, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max)
240{
241 if (*psz == ':' || *psz == '=')
242 psz++;
243 if (!*psz)
244 {
245 if (*pi + 1 >= argc)
246 return VBoxServiceSyntax("Missing value for the '%s' argument\n", argv[*pi]);
247 psz = argv[++*pi];
248 }
249
250 char *pszNext;
251 int rc = RTStrToUInt32Ex(psz, &pszNext, 0, pu32);
252 if (RT_FAILURE(rc) || *pszNext)
253 return VBoxServiceSyntax("Failed to convert interval '%s' to a number.\n", psz);
254 if (*pu32 < u32Min || *pu32 > u32Max)
255 return VBoxServiceSyntax("The timesync interval of %RU32 secconds is out of range [%RU32..%RU32].\n",
256 *pu32, u32Min, u32Max);
257 return 0;
258}
259
260
261/**
262 * The service thread.
263 *
264 * @returns Whatever the worker function returns.
265 * @param ThreadSelf My thread handle.
266 * @param pvUser The service index.
267 */
268static DECLCALLBACK(int) VBoxServiceThread(RTTHREAD ThreadSelf, void *pvUser)
269{
270 const unsigned i = (uintptr_t)pvUser;
271
272#ifndef RT_OS_WINDOWS
273 /*
274 * Block all signals for this thread. Only the main thread will handle signals.
275 */
276 sigset_t signalMask;
277 sigfillset(&signalMask);
278 pthread_sigmask(SIG_BLOCK, &signalMask, NULL);
279#endif
280
281 int rc = g_aServices[i].pDesc->pfnWorker(&g_aServices[i].fShutdown);
282 ASMAtomicXchgBool(&g_aServices[i].fShutdown, true);
283 RTThreadUserSignal(ThreadSelf);
284 return rc;
285}
286
287
288/**
289 * Check if at least one service should be started.
290 */
291static bool VBoxServiceCheckStartedServices(void)
292{
293 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
294 if (g_aServices[j].fEnabled)
295 return true;
296
297 return false;
298}
299
300
301/**
302 * Starts the service.
303 *
304 * @returns VBox status code, errors are fully bitched.
305 */
306int VBoxServiceStartServices(void)
307{
308 int rc;
309
310 /*
311 * Initialize the services.
312 */
313 VBoxServiceVerbose(2, "Initializing services ...\n");
314 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
315 if (g_aServices[j].fEnabled)
316 {
317 rc = g_aServices[j].pDesc->pfnInit();
318 if (RT_FAILURE(rc))
319 {
320 if (rc != VERR_SERVICE_DISABLED)
321 {
322 VBoxServiceError("Service '%s' failed to initialize: %Rrc\n",
323 g_aServices[j].pDesc->pszName, rc);
324 return rc;
325 }
326 g_aServices[j].fEnabled = false;
327 VBoxServiceVerbose(0, "Service '%s' was disabled because of missing functionality\n",
328 g_aServices[j].pDesc->pszName);
329
330 }
331 }
332
333 /*
334 * Start the service(s).
335 */
336 VBoxServiceVerbose(2, "Starting services ...\n");
337 rc = VINF_SUCCESS;
338 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
339 {
340 if (!g_aServices[j].fEnabled)
341 continue;
342
343 VBoxServiceVerbose(2, "Starting service '%s' ...\n", g_aServices[j].pDesc->pszName);
344 rc = RTThreadCreate(&g_aServices[j].Thread, VBoxServiceThread, (void *)(uintptr_t)j, 0,
345 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, g_aServices[j].pDesc->pszName);
346 if (RT_FAILURE(rc))
347 {
348 VBoxServiceError("RTThreadCreate failed, rc=%Rrc\n", rc);
349 break;
350 }
351 g_aServices[j].fStarted = true;
352
353 /* wait for the thread to initialize */
354 RTThreadUserWait(g_aServices[j].Thread, 60 * 1000);
355 if (g_aServices[j].fShutdown)
356 {
357 VBoxServiceError("Service '%s' failed to start!\n", g_aServices[j].pDesc->pszName);
358 rc = VERR_GENERAL_FAILURE;
359 }
360 }
361
362 return rc;
363}
364
365
366/**
367 * Stops and terminates the services.
368 *
369 * This should be called even when VBoxServiceStartServices fails so it can
370 * clean up anything that we succeeded in starting.
371 */
372int VBoxServiceStopServices(void)
373{
374 int rc = VINF_SUCCESS;
375
376 /*
377 * Signal all the services.
378 */
379 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
380 ASMAtomicWriteBool(&g_aServices[j].fShutdown, true);
381
382 /*
383 * Do the pfnStop callback on all running services.
384 */
385 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
386 if (g_aServices[j].fStarted)
387 {
388 VBoxServiceVerbose(3, "Calling stop function for service '%s' ...\n", g_aServices[j].pDesc->pszName);
389 g_aServices[j].pDesc->pfnStop();
390 }
391
392 /*
393 * Wait for all the service threads to complete.
394 */
395 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
396 {
397 if (!g_aServices[j].fEnabled) /* Only stop services which were started before. */
398 continue;
399 if (g_aServices[j].Thread != NIL_RTTHREAD)
400 {
401 VBoxServiceVerbose(2, "Waiting for service '%s' to stop ...\n", g_aServices[j].pDesc->pszName);
402 for (int i = 0; i < 30; i++) /* Wait 30 seconds in total */
403 {
404 rc = RTThreadWait(g_aServices[j].Thread, 1000 /* Wait 1 second */, NULL);
405 if (RT_SUCCESS(rc))
406 break;
407#ifdef RT_OS_WINDOWS
408 /* Notify SCM that it takes a bit longer ... */
409 VBoxServiceWinSetStopPendingStatus(i + j*32);
410#endif
411 }
412 if (RT_FAILURE(rc))
413 VBoxServiceError("Service '%s' failed to stop. (%Rrc)\n", g_aServices[j].pDesc->pszName, rc);
414 }
415 VBoxServiceVerbose(3, "Terminating service '%s' (%d) ...\n", g_aServices[j].pDesc->pszName, j);
416 g_aServices[j].pDesc->pfnTerm();
417 }
418
419#ifdef RT_OS_WINDOWS
420 /*
421 * Wake up and tell the main() thread that we're shutting down (it's
422 * sleeping in VBoxServiceMainWait).
423 */
424 if (g_hEvtWindowsService != NIL_RTSEMEVENT)
425 {
426 VBoxServiceVerbose(3, "Stopping the main thread...\n");
427 ASMAtomicWriteBool(&g_fWindowsServiceShutdown, true);
428 rc = RTSemEventSignal(g_hEvtWindowsService);
429 AssertRC(rc);
430 }
431#endif
432
433 VBoxServiceVerbose(2, "Stopping services returned: rc=%Rrc\n", rc);
434 return rc;
435}
436
437
438/**
439 * Block the main thread until the service shuts down.
440 */
441void VBoxServiceMainWait(void)
442{
443 int rc;
444
445 /* Report the host that we're up and running! */
446 rc = VbglR3ReportAdditionsStatus(VBoxGuestStatusFacility_VBoxService,
447 VBoxGuestStatusCurrent_Active,
448 0); /* Flags; not used. */
449 if (RT_FAILURE(rc))
450 VBoxServiceError("Failed to report Guest Additions status to the host! rc=%Rrc\n", rc);
451
452#ifdef RT_OS_WINDOWS
453 /*
454 * Wait for the semaphore to be signalled.
455 */
456 VBoxServiceVerbose(1, "Waiting in main thread\n");
457 rc = RTSemEventCreate(&g_hEvtWindowsService);
458 AssertRC(rc);
459 while (!ASMAtomicReadBool(&g_fWindowsServiceShutdown))
460 {
461 rc = RTSemEventWait(g_hEvtWindowsService, RT_INDEFINITE_WAIT);
462 AssertRC(rc);
463 }
464 RTSemEventDestroy(g_hEvtWindowsService);
465 g_hEvtWindowsService = NIL_RTSEMEVENT;
466
467#else
468 /*
469 * Wait explicitly for a HUP, INT, QUIT, ABRT or TERM signal, blocking
470 * all important signals.
471 *
472 * The annoying EINTR/ERESTART loop is for the benefit of Solaris where
473 * sigwait returns when we receive a SIGCHLD. Kind of makes sense since
474 */
475 sigset_t signalMask;
476 sigemptyset(&signalMask);
477 sigaddset(&signalMask, SIGHUP);
478 sigaddset(&signalMask, SIGINT);
479 sigaddset(&signalMask, SIGQUIT);
480 sigaddset(&signalMask, SIGABRT);
481 sigaddset(&signalMask, SIGTERM);
482 pthread_sigmask(SIG_BLOCK, &signalMask, NULL);
483
484 int iSignal;
485 do
486 {
487 iSignal = -1;
488 rc = sigwait(&signalMask, &iSignal);
489 }
490 while ( rc == EINTR
491# ifdef ERESTART
492 || rc == ERESTART
493# endif
494 );
495
496 VBoxServiceVerbose(3, "VBoxServiceMainWait: Received signal %d (rc=%d)\n", iSignal, rc);
497#endif /* !RT_OS_WINDOWS */
498}
499
500
501int main(int argc, char **argv)
502{
503 /*
504 * Init globals and such.
505 */
506 RTR3Init();
507
508 /*
509 * Connect to the kernel part before daemonizing so we can fail and
510 * complain if there is some kind of problem. We need to initialize the
511 * guest lib *before* we do the pre-init just in case one of services needs
512 * do to some initial stuff with it.
513 */
514 VBoxServiceVerbose(2, "Calling VbgR3Init()\n");
515 int rc = VbglR3Init();
516 if (RT_FAILURE(rc))
517 return VBoxServiceError("VbglR3Init failed with rc=%Rrc.\n", rc);
518
519#ifdef RT_OS_WINDOWS
520 /*
521 * Check if we're the specially spawned VBoxService.exe process that
522 * handles page fusion. This saves an extra executable.
523 */
524 if ( argc == 2
525 && !strcmp(argv[1], "--pagefusionfork"))
526 return VBoxServicePageSharingInitFork();
527#endif
528
529 g_pszProgName = RTPathFilename(argv[0]);
530
531#ifdef VBOXSERVICE_TOOLBOX
532 if (argc > 1)
533 {
534 /*
535 * Run toolbox code before all other stuff, especially before checking the global
536 * mutex because VBoxService might spawn itself to execute some commands.
537 */
538 rc = VBoxServiceToolboxMain(argc - 1, &argv[1]);
539 if (rc != VERR_NOT_FOUND) /* Internal tool found? Then bail out. */
540 return rc;
541 }
542#endif
543
544 /*
545 * Do pre-init of services.
546 */
547 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
548 {
549 rc = g_aServices[j].pDesc->pfnPreInit();
550 if (RT_FAILURE(rc))
551 return VBoxServiceError("Service '%s' failed pre-init: %Rrc\n", g_aServices[j].pDesc->pszName, rc);
552 }
553#ifdef RT_OS_WINDOWS
554 /*
555 * Make sure only one instance of VBoxService runs at a time. Create a
556 * global mutex for that. Do not use a global namespace ("Global\\") for
557 * mutex name here, will blow up NT4 compatibility!
558 */
559 /** @todo r=bird: Use Global\\ prefix or this serves no purpose on terminal servers. */
560 HANDLE hMutexAppRunning = CreateMutex(NULL, FALSE, VBOXSERVICE_NAME);
561 if ( hMutexAppRunning != NULL
562 && GetLastError() == ERROR_ALREADY_EXISTS)
563 {
564 VBoxServiceError("%s is already running! Terminating.", g_pszProgName);
565
566 /* Close the mutex for this application instance. */
567 CloseHandle(hMutexAppRunning);
568 hMutexAppRunning = NULL;
569
570 /** @todo r=bird: How does this cause us to terminate? Btw. Why do
571 * we do this before parsing parameters? 'VBoxService --help'
572 * and 'VBoxService --version' won't work now when the service
573 * is running... */
574 }
575#endif
576
577 /*
578 * Parse the arguments.
579 */
580 bool fDaemonize = true;
581 bool fDaemonized = false;
582 for (int i = 1; i < argc; i++)
583 {
584 const char *psz = argv[i];
585 if (*psz != '-')
586 return VBoxServiceSyntax("Unknown argument '%s'\n", psz);
587 psz++;
588
589 /* translate long argument to short */
590 if (*psz == '-')
591 {
592 psz++;
593 size_t cch = strlen(psz);
594#define MATCHES(strconst) ( cch == sizeof(strconst) - 1 \
595 && !memcmp(psz, strconst, sizeof(strconst) - 1) )
596 if (MATCHES("foreground"))
597 psz = "f";
598 else if (MATCHES("verbose"))
599 psz = "v";
600 else if (MATCHES("help"))
601 psz = "h";
602 else if (MATCHES("interval"))
603 psz = "i";
604#ifdef RT_OS_WINDOWS
605 else if (MATCHES("register"))
606 psz = "r";
607 else if (MATCHES("unregister"))
608 psz = "u";
609#endif
610 else if (MATCHES("daemonized"))
611 {
612 fDaemonized = true;
613 continue;
614 }
615 else
616 {
617 bool fFound = false;
618
619 if (cch > sizeof("enable-") && !memcmp(psz, "enable-", sizeof("enable-") - 1))
620 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
621 if ((fFound = !RTStrICmp(psz + sizeof("enable-") - 1, g_aServices[j].pDesc->pszName)))
622 g_aServices[j].fEnabled = true;
623
624 if (cch > sizeof("disable-") && !memcmp(psz, "disable-", sizeof("disable-") - 1))
625 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
626 if ((fFound = !RTStrICmp(psz + sizeof("disable-") - 1, g_aServices[j].pDesc->pszName)))
627 g_aServices[j].fEnabled = false;
628
629 if (!fFound)
630 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
631 {
632 rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i);
633 fFound = rc == 0;
634 if (fFound)
635 break;
636 if (rc != -1)
637 return rc;
638 }
639 if (!fFound)
640 return VBoxServiceSyntax("Unknown option '%s'\n", argv[i]);
641 continue;
642 }
643#undef MATCHES
644 }
645
646 /* handle the string of short options. */
647 do
648 {
649 switch (*psz)
650 {
651 case 'i':
652 rc = VBoxServiceArgUInt32(argc, argv, psz + 1, &i,
653 &g_DefaultInterval, 1, (UINT32_MAX / 1000) - 1);
654 if (rc)
655 return rc;
656 psz = NULL;
657 break;
658
659 case 'f':
660 fDaemonize = false;
661 break;
662
663 case 'v':
664 g_cVerbosity++;
665 break;
666
667 case 'h':
668 case '?':
669 return VBoxServiceUsage();
670
671#ifdef RT_OS_WINDOWS
672 case 'r':
673 return VBoxServiceWinInstall();
674
675 case 'u':
676 return VBoxServiceWinUninstall();
677#endif
678
679 default:
680 {
681 bool fFound = false;
682 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
683 {
684 rc = g_aServices[j].pDesc->pfnOption(&psz, argc, argv, &i);
685 fFound = rc == 0;
686 if (fFound)
687 break;
688 if (rc != -1)
689 return rc;
690 }
691 if (!fFound)
692 return VBoxServiceSyntax("Unknown option '%c' (%s)\n", *psz, argv[i]);
693 break;
694 }
695 }
696 } while (psz && *++psz);
697 }
698 /*
699 * Check that at least one service is enabled.
700 */
701 if (!VBoxServiceCheckStartedServices())
702 return VBoxServiceSyntax("At least one service must be enabled.\n");
703
704 VBoxServiceVerbose(0, "%s r%s started. Verbose level = %d\n",
705 RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity);
706
707 /*
708 * Daemonize if requested.
709 */
710 RTEXITCODE rcExit;
711 if (fDaemonize && !fDaemonized)
712 {
713#ifdef RT_OS_WINDOWS
714 VBoxServiceVerbose(2, "Starting service dispatcher ...\n");
715 rcExit = VBoxServiceWinEnterCtrlDispatcher();
716#else
717 VBoxServiceVerbose(1, "Daemonizing...\n");
718 rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */);
719 if (RT_FAILURE(rc))
720 return VBoxServiceError("Daemon failed: %Rrc\n", rc);
721 /* in-child */
722#endif
723 }
724#ifdef RT_OS_WINDOWS
725 else
726#endif
727 {
728 /*
729 * Windows: We're running the service as a console application now. Start the
730 * services, enter the main thread's run loop and stop them again
731 * when it returns.
732 *
733 * POSIX: This is used for both daemons and console runs. Start all services
734 * and return immediately.
735 */
736 rc = VBoxServiceStartServices();
737 rcExit = RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
738 if (RT_SUCCESS(rc))
739 VBoxServiceMainWait();
740 VBoxServiceStopServices();
741 }
742
743#ifdef RT_OS_WINDOWS
744 /*
745 * Release instance mutex if we got it.
746 */
747 if (hMutexAppRunning != NULL)
748 {
749 ::CloseHandle(hMutexAppRunning);
750 hMutexAppRunning = NULL;
751 }
752#endif
753
754 VBoxServiceVerbose(0, "Ended.\n");
755 return rcExit;
756}
757
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