VirtualBox

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

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

Spawn 2nd VBoxService instance to handle page fusion in order to work around issues when loading dlls with the
DONT_RESOLVE_DLL_REFERENCES flag.

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