VirtualBox

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

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

VBoxService: Another shot at the solaris SIGCHLD/exec problem.

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