VirtualBox

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

Last change on this file since 29776 was 29776, checked in by vboxsync, 15 years ago

VBoxService.cpp: nits

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.3 KB
Line 
1/* $Id: VBoxService.cpp 29776 2010-05-25 11:38:17Z 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. */
59bool volatile g_WindowsServiceShutdown;
60/** Event the Windows service thread waits for shutdown. */
61RTSEMEVENT g_WindowsServiceEvent;
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 1
158 * @param pszFormat The message text.
159 * @param ... Format arguments.
160 */
161int 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 1;
171}
172
173
174/**
175 * Displays an error message.
176 *
177 * @returns 1
178 * @param pszFormat The message text.
179 * @param ... Format arguments.
180 */
181int 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 1;
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 {
311 if (g_aServices[j].fEnabled)
312 {
313 rc = g_aServices[j].pDesc->pfnInit();
314 if (RT_FAILURE(rc))
315 {
316 if (rc != VERR_SERVICE_DISABLED)
317 {
318 VBoxServiceError("Service '%s' failed to initialize: %Rrc\n",
319 g_aServices[j].pDesc->pszName, rc);
320 return rc;
321 }
322 g_aServices[j].fEnabled = false;
323 VBoxServiceVerbose(0, "Service '%s' was disabled because of missing functionality\n",
324 g_aServices[j].pDesc->pszName);
325
326 }
327 }
328 }
329
330 /*
331 * Start the service(s).
332 */
333 VBoxServiceVerbose(2, "Starting services ...\n");
334 rc = VINF_SUCCESS;
335 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
336 {
337 if (!g_aServices[j].fEnabled)
338 continue;
339
340 VBoxServiceVerbose(2, "Starting service '%s' ...\n", g_aServices[j].pDesc->pszName);
341 rc = RTThreadCreate(&g_aServices[j].Thread, VBoxServiceThread, (void *)(uintptr_t)j, 0,
342 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, g_aServices[j].pDesc->pszName);
343 if (RT_FAILURE(rc))
344 {
345 VBoxServiceError("RTThreadCreate failed, rc=%Rrc\n", rc);
346 break;
347 }
348 g_aServices[j].fStarted = true;
349
350 /* wait for the thread to initialize */
351 RTThreadUserWait(g_aServices[j].Thread, 60 * 1000);
352 if (g_aServices[j].fShutdown)
353 {
354 VBoxServiceError("Service '%s' failed to start!\n", g_aServices[j].pDesc->pszName);
355 rc = VERR_GENERAL_FAILURE;
356 }
357 }
358
359#ifdef RT_OS_WINDOWS
360 if (RT_SUCCESS(rc))
361 {
362 /* Block the main thread. */
363 VBoxServiceVerbose(1, "Waiting in main thread\n");
364 int rc = RTSemEventCreate(&g_WindowsServiceEvent);
365 AssertRC(rc);
366 for (;;)
367 {
368 if (g_WindowsServiceShutdown)
369 break;
370 rc = RTSemEventWait(g_WindowsServiceEvent, RT_INDEFINITE_WAIT);
371 AssertRC(rc);
372 }
373 RTSemEventDestroy(g_WindowsServiceEvent);
374 g_WindowsServiceEvent = NIL_RTSEMEVENT;
375 }
376#endif
377 return rc;
378}
379
380
381/**
382 * Stops and terminates the services.
383 *
384 * This should be called even when VBoxServiceStartServices fails so it can
385 * clean up anything that we succeeded in starting.
386 */
387int VBoxServiceStopServices(void)
388{
389 int rc = VINF_SUCCESS;
390
391 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
392 ASMAtomicXchgBool(&g_aServices[j].fShutdown, true);
393 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
394 if (g_aServices[j].fStarted)
395 {
396 VBoxServiceVerbose(3, "Calling stop function for service '%s' ...\n", g_aServices[j].pDesc->pszName);
397 g_aServices[j].pDesc->pfnStop();
398 }
399 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
400 {
401 if (!g_aServices[j].fEnabled) /* Only stop services which were started before. */
402 continue;
403 if (g_aServices[j].Thread != NIL_RTTHREAD)
404 {
405 VBoxServiceVerbose(2, "Waiting for service '%s' to stop ...\n", g_aServices[j].pDesc->pszName);
406 for (int i = 0; i < 30; i++) /* Wait 30 seconds in total */
407 {
408 rc = RTThreadWait(g_aServices[j].Thread, 1000 /* Wait 1 second */, NULL);
409 if (RT_SUCCESS(rc))
410 break;
411#ifdef RT_OS_WINDOWS
412 /* Notify SCM that it takes a bit longer ... */
413 VBoxServiceWinSetStatus(SERVICE_STOP_PENDING, i);
414#endif
415 }
416 if (RT_FAILURE(rc))
417 VBoxServiceError("Service '%s' failed to stop. (%Rrc)\n", g_aServices[j].pDesc->pszName, rc);
418 }
419 VBoxServiceVerbose(3, "Terminating service '%s' (%d) ...\n", g_aServices[j].pDesc->pszName, j);
420 g_aServices[j].pDesc->pfnTerm();
421 }
422
423#ifdef RT_OS_WINDOWS
424 /*
425 * As we're now done terminating all service threads,
426 * we have to stop the main thread as well (if defined). Note that the termination
427 * function will be called in a later context (when the main thread returns from the worker
428 * function).
429 */
430 if (g_WindowsServiceEvent != NIL_RTSEMEVENT)
431 {
432 VBoxServiceVerbose(3, "Stopping the main thread...\n");
433 ASMAtomicXchgBool(&g_WindowsServiceShutdown, true);
434 rc = RTSemEventSignal(g_WindowsServiceEvent);
435 AssertRC(rc);
436 }
437#endif
438
439 VBoxServiceVerbose(2, "Stopping services returned: rc=%Rrc\n", rc);
440 return rc;
441}
442
443
444#ifndef RT_OS_WINDOWS
445/**
446 * Block all important signals, then explicitly wait until one of these
447 * signal arrives.
448 */
449static void VBoxServiceWaitSignal(void)
450{
451 sigset_t signalMask;
452 int iSignal;
453 sigemptyset(&signalMask);
454 sigaddset(&signalMask, SIGHUP);
455 sigaddset(&signalMask, SIGINT);
456 sigaddset(&signalMask, SIGQUIT);
457 sigaddset(&signalMask, SIGABRT);
458 sigaddset(&signalMask, SIGTERM);
459 pthread_sigmask(SIG_BLOCK, &signalMask, NULL);
460
461 /* This loop is required on Solaris at least. FreeBSD doesn't know ERESTART. */
462 int rc;
463 do
464 {
465 iSignal = -1;
466 rc = sigwait(&signalMask, &iSignal);
467 }
468 while ( rc == EINTR
469# ifdef ERESTART
470 || rc == ERESTART
471# endif
472 );
473
474 VBoxServiceVerbose(3, "VBoxServiceWaitSignal: Received signal %d (rc=%d)\n", iSignal, rc);
475}
476#endif /* !RT_OS_WINDOWS */
477
478
479int main(int argc, char **argv)
480{
481 int rc = VINF_SUCCESS;
482 /*
483 * Init globals and such.
484 */
485 RTR3Init();
486
487 /*
488 * Connect to the kernel part before daemonizing so we can fail
489 * and complain if there is some kind of problem. We need to initialize
490 * the guest lib *before* we do the pre-init just in case one of services
491 * needs do to some initial stuff with it.
492 */
493 VBoxServiceVerbose(2, "Calling VbgR3Init()\n");
494 rc = VbglR3Init();
495 if (RT_FAILURE(rc))
496 return VBoxServiceError("VbglR3Init failed with rc=%Rrc.\n", rc);
497
498 /* Do pre-init of services. */
499 g_pszProgName = RTPathFilename(argv[0]);
500 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
501 {
502 rc = g_aServices[j].pDesc->pfnPreInit();
503 if (RT_FAILURE(rc))
504 return VBoxServiceError("Service '%s' failed pre-init: %Rrc\n", g_aServices[j].pDesc->pszName);
505 }
506
507#ifdef RT_OS_WINDOWS
508 /* Make sure only one instance of VBoxService runs at a time. Create a global mutex for that.
509 Do not use a global namespace ("Global\\") for mutex name here, will blow up NT4 compatibility! */
510 HANDLE hMutexAppRunning = CreateMutex (NULL, FALSE, VBOXSERVICE_NAME);
511 if ( hMutexAppRunning != NULL
512 && GetLastError() == ERROR_ALREADY_EXISTS)
513 {
514 VBoxServiceError("%s is already running! Terminating.", g_pszProgName);
515
516 /* Close the mutex for this application instance. */
517 CloseHandle(hMutexAppRunning);
518 hMutexAppRunning = NULL;
519 }
520#endif
521
522 /*
523 * Parse the arguments.
524 */
525 bool fDaemonize = true;
526 bool fDaemonized = false;
527 for (int i = 1; i < argc; i++)
528 {
529 const char *psz = argv[i];
530 if (*psz != '-')
531 return VBoxServiceSyntax("Unknown argument '%s'\n", psz);
532 psz++;
533
534 /* translate long argument to short */
535 if (*psz == '-')
536 {
537 psz++;
538 size_t cch = strlen(psz);
539#define MATCHES(strconst) ( cch == sizeof(strconst) - 1 \
540 && !memcmp(psz, strconst, sizeof(strconst) - 1) )
541 if (MATCHES("foreground"))
542 psz = "f";
543 else if (MATCHES("verbose"))
544 psz = "v";
545 else if (MATCHES("help"))
546 psz = "h";
547 else if (MATCHES("interval"))
548 psz = "i";
549#ifdef RT_OS_WINDOWS
550 else if (MATCHES("register"))
551 psz = "r";
552 else if (MATCHES("unregister"))
553 psz = "u";
554#endif
555 else if (MATCHES("daemonized"))
556 {
557 fDaemonized = true;
558 continue;
559 }
560 else
561 {
562 bool fFound = false;
563
564 if (cch > sizeof("enable-") && !memcmp(psz, "enable-", sizeof("enable-") - 1))
565 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
566 if ((fFound = !RTStrICmp(psz + sizeof("enable-") - 1, g_aServices[j].pDesc->pszName)))
567 g_aServices[j].fEnabled = true;
568
569 if (cch > sizeof("disable-") && !memcmp(psz, "disable-", sizeof("disable-") - 1))
570 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
571 if ((fFound = !RTStrICmp(psz + sizeof("disable-") - 1, g_aServices[j].pDesc->pszName)))
572 g_aServices[j].fEnabled = false;
573
574 if (!fFound)
575 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
576 {
577 rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i);
578 fFound = rc == 0;
579 if (fFound)
580 break;
581 if (rc != -1)
582 return rc;
583 }
584 if (!fFound)
585 return VBoxServiceSyntax("Unknown option '%s'\n", argv[i]);
586 continue;
587 }
588#undef MATCHES
589 }
590
591 /* handle the string of short options. */
592 do
593 {
594 switch (*psz)
595 {
596 case 'i':
597 rc = VBoxServiceArgUInt32(argc, argv, psz + 1, &i,
598 &g_DefaultInterval, 1, (UINT32_MAX / 1000) - 1);
599 if (rc)
600 return rc;
601 psz = NULL;
602 break;
603
604 case 'f':
605 fDaemonize = false;
606 break;
607
608 case 'v':
609 g_cVerbosity++;
610 break;
611
612 case 'h':
613 case '?':
614 return VBoxServiceUsage();
615
616#ifdef RT_OS_WINDOWS
617 case 'r':
618 return VBoxServiceWinInstall();
619
620 case 'u':
621 return VBoxServiceWinUninstall();
622#endif
623
624 default:
625 {
626 bool fFound = false;
627 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
628 {
629 rc = g_aServices[j].pDesc->pfnOption(&psz, argc, argv, &i);
630 fFound = rc == 0;
631 if (fFound)
632 break;
633 if (rc != -1)
634 return rc;
635 }
636 if (!fFound)
637 return VBoxServiceSyntax("Unknown option '%c' (%s)\n", *psz, argv[i]);
638 break;
639 }
640 }
641 } while (psz && *++psz);
642 }
643 /*
644 * Check that at least one service is enabled.
645 */
646 if (!VBoxServiceCheckStartedServices())
647 return VBoxServiceSyntax("At least one service must be enabled.\n");
648
649 VBoxServiceVerbose(0, "%s r%s started. Verbose level = %d\n",
650 RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity);
651
652 /*
653 * Daemonize if requested.
654 */
655 if (fDaemonize && !fDaemonized)
656 {
657#ifdef RT_OS_WINDOWS
658 /** @todo Should do something like VBoxSVC here, OR automatically re-register
659 * the service and start it. Involving VbglR3Daemonize isn't an option
660 * here.
661 *
662 * Also, the idea here, IIRC, was to map the sub service to windows
663 * services. The todo below is for mimicking windows services on
664 * non-windows systems. Not sure if this is doable or not, but in anycase
665 * this code can be moved into -win.
666 *
667 * You should return when StartServiceCtrlDispatcher, btw., not
668 * continue.
669 */
670 VBoxServiceVerbose(2, "Starting service dispatcher ...\n");
671 if (!StartServiceCtrlDispatcher(&g_aServiceTable[0]))
672 return VBoxServiceError("StartServiceCtrlDispatcher: %u. Please start %s with option -f (foreground)!",
673 GetLastError(), g_pszProgName);
674 /* Service now lives in the control dispatcher registered above. */
675#else
676 VBoxServiceVerbose(1, "Daemonizing...\n");
677 rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */);
678 if (RT_FAILURE(rc))
679 return VBoxServiceError("Daemon failed: %Rrc\n", rc);
680 /* in-child */
681#endif
682 }
683#ifdef RT_OS_WINDOWS
684 else
685#endif
686 {
687 /*
688 * Windows: We're running the service as a console application now. Start the
689 * services, enter the main thread's run loop and stop them again
690 * when it returns.
691 *
692 * POSIX: This is used for both daemons and console runs. Start all services
693 * and return immediately.
694 */
695 rc = VBoxServiceStartServices();
696#ifndef RT_OS_WINDOWS
697 if (RT_SUCCESS(rc))
698 VBoxServiceWaitSignal();
699#endif
700 VBoxServiceStopServices();
701 }
702
703#ifdef RT_OS_WINDOWS
704 /*
705 * Release instance mutex if we got it.
706 */
707 if (hMutexAppRunning != NULL)
708 {
709 ::CloseHandle(hMutexAppRunning);
710 hMutexAppRunning = NULL;
711 }
712#endif
713
714 VBoxServiceVerbose(0, "Ended.\n");
715 return RT_SUCCESS(rc) ? 0 : 1;
716}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette