VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/xpcom/server.cpp@ 78273

Last change on this file since 78273 was 76592, checked in by vboxsync, 6 years ago

Main: Don't use Logging.h.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.0 KB
Line 
1/* $Id: server.cpp 76592 2019-01-01 20:13:07Z vboxsync $ */
2/** @file
3 * XPCOM server process (VBoxSVC) start point.
4 */
5
6/*
7 * Copyright (C) 2004-2019 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#define LOG_GROUP LOG_GROUP_MAIN_VBOXSVC
19#include <ipcIService.h>
20#include <ipcCID.h>
21
22#include <nsIComponentRegistrar.h>
23
24#include <nsGenericFactory.h>
25
26#include "prio.h"
27#include "prproces.h"
28
29#include "server.h"
30
31#include "LoggingNew.h"
32
33#include <VBox/param.h>
34
35#include <iprt/buildconfig.h>
36#include <iprt/initterm.h>
37#include <iprt/critsect.h>
38#include <iprt/getopt.h>
39#include <iprt/message.h>
40#include <iprt/string.h>
41#include <iprt/stream.h>
42#include <iprt/path.h>
43#include <iprt/timer.h>
44#include <iprt/env.h>
45
46#include <signal.h> // for the signal handler
47#include <stdlib.h>
48#include <unistd.h>
49#include <errno.h>
50#include <fcntl.h>
51#include <sys/stat.h>
52#include <sys/resource.h>
53
54/////////////////////////////////////////////////////////////////////////////
55// VirtualBox component instantiation
56/////////////////////////////////////////////////////////////////////////////
57
58#include <nsIGenericFactory.h>
59#include <VBox/com/VirtualBox.h>
60
61#include "VBox/com/NativeEventQueue.h"
62
63#include "ApplianceImpl.h"
64#include "AudioAdapterImpl.h"
65#include "BandwidthControlImpl.h"
66#include "BandwidthGroupImpl.h"
67#include "NetworkServiceRunner.h"
68#include "DHCPServerImpl.h"
69#include "GuestOSTypeImpl.h"
70#include "HostImpl.h"
71#include "HostNetworkInterfaceImpl.h"
72#include "MachineImpl.h"
73#include "MediumFormatImpl.h"
74#include "MediumImpl.h"
75#include "NATEngineImpl.h"
76#include "NetworkAdapterImpl.h"
77#include "ParallelPortImpl.h"
78#include "ProgressProxyImpl.h"
79#include "SerialPortImpl.h"
80#include "SharedFolderImpl.h"
81#include "SnapshotImpl.h"
82#include "StorageControllerImpl.h"
83#include "SystemPropertiesImpl.h"
84#include "USBControllerImpl.h"
85#include "USBDeviceFiltersImpl.h"
86#include "VFSExplorerImpl.h"
87#include "VirtualBoxImpl.h"
88#include "VRDEServerImpl.h"
89#ifdef VBOX_WITH_USB
90# include "HostUSBDeviceImpl.h"
91# include "USBDeviceFilterImpl.h"
92# include "USBDeviceImpl.h"
93#endif
94#ifdef VBOX_WITH_EXTPACK
95# include "ExtPackManagerImpl.h"
96#endif
97# include "NATNetworkImpl.h"
98
99// This needs to stay - it is needed by the service registration below, and
100// is defined in the automatically generated VirtualBoxWrap.cpp
101extern nsIClassInfo *NS_CLASSINFO_NAME(VirtualBoxWrap);
102NS_DECL_CI_INTERFACE_GETTER(VirtualBoxWrap)
103
104////////////////////////////////////////////////////////////////////////////////
105
106static bool gAutoShutdown = false;
107/** Delay before shutting down the VirtualBox server after the last
108 * VirtualBox instance is released, in ms */
109static uint32_t gShutdownDelayMs = 5000;
110
111static com::NativeEventQueue *gEventQ = NULL;
112static PRBool volatile gKeepRunning = PR_TRUE;
113static PRBool volatile gAllowSigUsrQuit = PR_TRUE;
114
115/////////////////////////////////////////////////////////////////////////////
116
117/**
118 * VirtualBox class factory that destroys the created instance right after
119 * the last reference to it is released by the client, and recreates it again
120 * when necessary (so VirtualBox acts like a singleton object).
121 */
122class VirtualBoxClassFactory : public VirtualBox
123{
124public:
125
126 virtual ~VirtualBoxClassFactory()
127 {
128 LogFlowFunc(("Deleting VirtualBox...\n"));
129
130 FinalRelease();
131 sInstance = NULL;
132
133 LogFlowFunc(("VirtualBox object deleted.\n"));
134 RTPrintf("Informational: VirtualBox object deleted.\n");
135 }
136
137 NS_IMETHOD_(nsrefcnt) Release()
138 {
139 /* we overload Release() to guarantee the VirtualBox destructor is
140 * always called on the main thread */
141
142 nsrefcnt count = VirtualBox::Release();
143
144 if (count == 1)
145 {
146 /* the last reference held by clients is being released
147 * (see GetInstance()) */
148
149 bool onMainThread = RTThreadIsMain(RTThreadSelf());
150 PRBool timerStarted = PR_FALSE;
151
152 /* sTimer is null if this call originates from FactoryDestructor()*/
153 if (sTimer != NULL)
154 {
155 LogFlowFunc(("Last VirtualBox instance was released.\n"));
156 LogFlowFunc(("Scheduling server shutdown in %u ms...\n",
157 gShutdownDelayMs));
158
159 /* make sure the previous timer (if any) is stopped;
160 * otherwise RTTimerStart() will definitely fail. */
161 RTTimerLRStop(sTimer);
162
163 int vrc = RTTimerLRStart(sTimer, gShutdownDelayMs * RT_NS_1MS_64);
164 AssertRC(vrc);
165 timerStarted = !!(SUCCEEDED(vrc));
166 }
167 else
168 {
169 LogFlowFunc(("Last VirtualBox instance was released "
170 "on XPCOM shutdown.\n"));
171 Assert(onMainThread);
172 }
173
174 gAllowSigUsrQuit = PR_TRUE;
175
176 if (!timerStarted)
177 {
178 if (!onMainThread)
179 {
180 /* Failed to start the timer, post the shutdown event
181 * manually if not on the main thread already. */
182 ShutdownTimer(NULL, NULL, 0);
183 }
184 else
185 {
186 /* Here we come if:
187 *
188 * a) gEventQ is 0 which means either FactoryDestructor() is called
189 * or the IPC/DCONNECT shutdown sequence is initiated by the
190 * XPCOM shutdown routine (NS_ShutdownXPCOM()), which always
191 * happens on the main thread.
192 *
193 * b) gEventQ has reported we're on the main thread. This means
194 * that DestructEventHandler() has been called, but another
195 * client was faster and requested VirtualBox again.
196 *
197 * In either case, there is nothing to do.
198 *
199 * Note: case b) is actually no more valid since we don't
200 * call Release() from DestructEventHandler() in this case
201 * any more. Thus, we assert below.
202 */
203
204 Assert(!gEventQ);
205 }
206 }
207 }
208
209 return count;
210 }
211
212 class MaybeQuitEvent : public NativeEvent
213 {
214 public:
215 MaybeQuitEvent() :
216 m_fSignal(false)
217 {
218 }
219
220 MaybeQuitEvent(bool fSignal) :
221 m_fSignal(fSignal)
222 {
223 }
224
225 private:
226 /* called on the main thread */
227 void *handler()
228 {
229 LogFlowFuncEnter();
230
231 Assert(RTCritSectIsInitialized(&sLock));
232
233 /* stop accepting GetInstance() requests on other threads during
234 * possible destruction */
235 RTCritSectEnter(&sLock);
236
237 nsrefcnt count = 1;
238
239 /* sInstance is NULL here if it was deleted immediately after
240 * creation due to initialization error. See GetInstance(). */
241 if (sInstance != NULL)
242 {
243 /* Safe way to get current refcount is by first increasing and
244 * then decreasing. Keep in mind that the Release is overloaded
245 * (see VirtualBoxClassFactory::Release) and will start the
246 * timer again if the returned count is 1. It won't do harm,
247 * but also serves no purpose, so stop it ASAP. */
248 sInstance->AddRef();
249 count = sInstance->Release();
250 if (count == 1)
251 {
252 RTTimerLRStop(sTimer);
253 /* Release the guard reference added in GetInstance() */
254 sInstance->Release();
255 }
256 }
257
258 if (count == 1)
259 {
260 if (gAutoShutdown || m_fSignal)
261 {
262 Assert(sInstance == NULL);
263 LogFlowFunc(("Terminating the server process...\n"));
264 /* make it leave the event loop */
265 gKeepRunning = PR_FALSE;
266 }
267 else
268 LogFlowFunc(("No automatic shutdown.\n"));
269 }
270 else
271 {
272 /* This condition is quite rare: a new client happened to
273 * connect after this event has been posted to the main queue
274 * but before it started to process it. */
275 LogRel(("Destruction is canceled (refcnt=%d).\n", count));
276 }
277
278 RTCritSectLeave(&sLock);
279
280 LogFlowFuncLeave();
281 return NULL;
282 }
283
284 bool m_fSignal;
285 };
286
287 static DECLCALLBACK(void) ShutdownTimer(RTTIMERLR hTimerLR, void *pvUser, uint64_t /*iTick*/)
288 {
289 NOREF(hTimerLR);
290 NOREF(pvUser);
291
292 /* A "too late" event is theoretically possible if somebody
293 * manually ended the server after a destruction has been scheduled
294 * and this method was so lucky that it got a chance to run before
295 * the timer was killed. */
296 com::NativeEventQueue *q = gEventQ;
297 AssertReturnVoid(q);
298
299 /* post a quit event to the main queue */
300 MaybeQuitEvent *ev = new MaybeQuitEvent(false /* fSignal */);
301 if (!q->postEvent(ev))
302 delete ev;
303
304 /* A failure above means we've been already stopped (for example
305 * by Ctrl-C). FactoryDestructor() (NS_ShutdownXPCOM())
306 * will do the job. Nothing to do. */
307 }
308
309 static NS_IMETHODIMP FactoryConstructor()
310 {
311 LogFlowFunc(("\n"));
312
313 /* create a critsect to protect object construction */
314 if (RT_FAILURE(RTCritSectInit(&sLock)))
315 return NS_ERROR_OUT_OF_MEMORY;
316
317 int vrc = RTTimerLRCreateEx(&sTimer, 0, 0, ShutdownTimer, NULL);
318 if (RT_FAILURE(vrc))
319 {
320 LogFlowFunc(("Failed to create a timer! (vrc=%Rrc)\n", vrc));
321 return NS_ERROR_FAILURE;
322 }
323
324 return NS_OK;
325 }
326
327 static NS_IMETHODIMP FactoryDestructor()
328 {
329 LogFlowFunc(("\n"));
330
331 RTTimerLRDestroy(sTimer);
332 sTimer = NULL;
333
334 if (sInstance != NULL)
335 {
336 /* Either posting a destruction event failed for some reason (most
337 * likely, the quit event has been received before the last release),
338 * or the client has terminated abnormally w/o releasing its
339 * VirtualBox instance (so NS_ShutdownXPCOM() is doing a cleanup).
340 * Release the guard reference we added in GetInstance(). */
341 sInstance->Release();
342 }
343
344 /* Destroy lock after releasing the VirtualBox instance, otherwise
345 * there are races with cleanup. */
346 RTCritSectDelete(&sLock);
347
348 return NS_OK;
349 }
350
351 static nsresult GetInstance(VirtualBox **inst)
352 {
353 LogFlowFunc(("Getting VirtualBox object...\n"));
354
355 RTCritSectEnter(&sLock);
356
357 if (!gKeepRunning)
358 {
359 LogFlowFunc(("Process termination requested first. Refusing.\n"));
360
361 RTCritSectLeave(&sLock);
362
363 /* this rv is what CreateInstance() on the client side returns
364 * when the server process stops accepting events. Do the same
365 * here. The client wrapper should attempt to start a new process in
366 * response to a failure from us. */
367 return NS_ERROR_ABORT;
368 }
369
370 nsresult rv = NS_OK;
371
372 if (sInstance == NULL)
373 {
374 LogFlowFunc(("Creating new VirtualBox object...\n"));
375 sInstance = new VirtualBoxClassFactory();
376 if (sInstance != NULL)
377 {
378 /* make an extra AddRef to take the full control
379 * on the VirtualBox destruction (see FinalRelease()) */
380 sInstance->AddRef();
381
382 sInstance->AddRef(); /* protect FinalConstruct() */
383 rv = sInstance->FinalConstruct();
384 RTPrintf("Informational: VirtualBox object created (rc=%Rhrc).\n", rv);
385 if (NS_FAILED(rv))
386 {
387 /* On failure diring VirtualBox initialization, delete it
388 * immediately on the current thread by releasing all
389 * references in order to properly schedule the server
390 * shutdown. Since the object is fully deleted here, there
391 * is a chance to fix the error and request a new
392 * instantiation before the server terminates. However,
393 * the main reason to maintain the shutdown delay on
394 * failure is to let the front-end completely fetch error
395 * info from a server-side IVirtualBoxErrorInfo object. */
396 sInstance->Release();
397 sInstance->Release();
398 Assert(sInstance == NULL);
399 }
400 else
401 {
402 /* On success, make sure the previous timer is stopped to
403 * cancel a scheduled server termination (if any). */
404 gAllowSigUsrQuit = PR_FALSE;
405 RTTimerLRStop(sTimer);
406 }
407 }
408 else
409 {
410 rv = NS_ERROR_OUT_OF_MEMORY;
411 }
412 }
413 else
414 {
415 LogFlowFunc(("Using existing VirtualBox object...\n"));
416 nsrefcnt count = sInstance->AddRef();
417 Assert(count > 1);
418
419 if (count >= 2)
420 {
421 LogFlowFunc(("Another client has requested a reference to VirtualBox, canceling destruction...\n"));
422
423 /* make sure the previous timer is stopped */
424 gAllowSigUsrQuit = PR_FALSE;
425 RTTimerLRStop(sTimer);
426 }
427 }
428
429 *inst = sInstance;
430
431 RTCritSectLeave(&sLock);
432
433 return rv;
434 }
435
436private:
437
438 /* Don't be confused that sInstance is of the *ClassFactory type. This is
439 * actually a singleton instance (*ClassFactory inherits the singleton
440 * class; we combined them just for "simplicity" and used "static" for
441 * factory methods. *ClassFactory here is necessary for a couple of extra
442 * methods. */
443
444 static VirtualBoxClassFactory *sInstance;
445 static RTCRITSECT sLock;
446
447 static RTTIMERLR sTimer;
448};
449
450VirtualBoxClassFactory *VirtualBoxClassFactory::sInstance = NULL;
451RTCRITSECT VirtualBoxClassFactory::sLock;
452
453RTTIMERLR VirtualBoxClassFactory::sTimer = NIL_RTTIMERLR;
454
455NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR_WITH_RC(VirtualBox, VirtualBoxClassFactory::GetInstance)
456
457////////////////////////////////////////////////////////////////////////////////
458
459typedef NSFactoryDestructorProcPtr NSFactoryConstructorProcPtr;
460
461/**
462 * Enhanced module component information structure.
463 *
464 * nsModuleComponentInfo lacks the factory construction callback, here we add
465 * it. This callback is called straight after a nsGenericFactory instance is
466 * successfully created in RegisterSelfComponents.
467 */
468struct nsModuleComponentInfoPlusFactoryConstructor
469{
470 /** standard module component information */
471 const nsModuleComponentInfo *mpModuleComponentInfo;
472 /** (optional) Factory Construction Callback */
473 NSFactoryConstructorProcPtr mFactoryConstructor;
474};
475
476/////////////////////////////////////////////////////////////////////////////
477
478/**
479 * Helper function to register self components upon start-up
480 * of the out-of-proc server.
481 */
482static nsresult
483RegisterSelfComponents(nsIComponentRegistrar *registrar,
484 const nsModuleComponentInfoPlusFactoryConstructor *aComponents,
485 PRUint32 count)
486{
487 nsresult rc = NS_OK;
488 const nsModuleComponentInfoPlusFactoryConstructor *info = aComponents;
489 for (PRUint32 i = 0; i < count && NS_SUCCEEDED(rc); i++, info++)
490 {
491 /* skip components w/o a constructor */
492 if (!info->mpModuleComponentInfo->mConstructor)
493 continue;
494 /* create a new generic factory for a component and register it */
495 nsIGenericFactory *factory;
496 rc = NS_NewGenericFactory(&factory, info->mpModuleComponentInfo);
497 if (NS_SUCCEEDED(rc) && info->mFactoryConstructor)
498 {
499 rc = info->mFactoryConstructor();
500 if (NS_FAILED(rc))
501 NS_RELEASE(factory);
502 }
503 if (NS_SUCCEEDED(rc))
504 {
505 rc = registrar->RegisterFactory(info->mpModuleComponentInfo->mCID,
506 info->mpModuleComponentInfo->mDescription,
507 info->mpModuleComponentInfo->mContractID,
508 factory);
509 NS_RELEASE(factory);
510 }
511 }
512 return rc;
513}
514
515/////////////////////////////////////////////////////////////////////////////
516
517static ipcIService *gIpcServ = nsnull;
518static const char *g_pszPidFile = NULL;
519
520class ForceQuitEvent : public NativeEvent
521{
522 void *handler()
523 {
524 LogFlowFunc(("\n"));
525
526 gKeepRunning = PR_FALSE;
527
528 if (g_pszPidFile)
529 RTFileDelete(g_pszPidFile);
530
531 return NULL;
532 }
533};
534
535static void signal_handler(int sig)
536{
537 com::NativeEventQueue *q = gEventQ;
538 if (q && gKeepRunning)
539 {
540 if (sig == SIGUSR1)
541 {
542 if (gAllowSigUsrQuit)
543 {
544 /* terminate the server process if it is idle */
545 VirtualBoxClassFactory::MaybeQuitEvent *ev = new VirtualBoxClassFactory::MaybeQuitEvent(true /* fSignal */);
546 if (!q->postEvent(ev))
547 delete ev;
548 }
549 /* else do nothing */
550 }
551 else
552 {
553 /* post a force quit event to the queue */
554 ForceQuitEvent *ev = new ForceQuitEvent();
555 if (!q->postEvent(ev))
556 delete ev;
557 }
558 }
559}
560
561static nsresult vboxsvcSpawnDaemonByReExec(const char *pszPath, bool fAutoShutdown, const char *pszPidFile)
562{
563 PRFileDesc *readable = nsnull, *writable = nsnull;
564 PRProcessAttr *attr = nsnull;
565 nsresult rv = NS_ERROR_FAILURE;
566 PRFileDesc *devNull;
567 unsigned args_index = 0;
568 // The ugly casts are necessary because the PR_CreateProcessDetached has
569 // a const array of writable strings as a parameter. It won't write. */
570 char * args[1 + 1 + 2 + 1];
571 args[args_index++] = (char *)pszPath;
572 if (fAutoShutdown)
573 args[args_index++] = (char *)"--auto-shutdown";
574 if (pszPidFile)
575 {
576 args[args_index++] = (char *)"--pidfile";
577 args[args_index++] = (char *)pszPidFile;
578 }
579 args[args_index++] = 0;
580
581 // Use a pipe to determine when the daemon process is in the position
582 // to actually process requests. The daemon will write "READY" to the pipe.
583 if (PR_CreatePipe(&readable, &writable) != PR_SUCCESS)
584 goto end;
585 PR_SetFDInheritable(writable, PR_TRUE);
586
587 attr = PR_NewProcessAttr();
588 if (!attr)
589 goto end;
590
591 if (PR_ProcessAttrSetInheritableFD(attr, writable, VBOXSVC_STARTUP_PIPE_NAME) != PR_SUCCESS)
592 goto end;
593
594 devNull = PR_Open("/dev/null", PR_RDWR, 0);
595 if (!devNull)
596 goto end;
597
598 PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, devNull);
599 PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, devNull);
600 PR_ProcessAttrSetStdioRedirect(attr, PR_StandardError, devNull);
601
602 if (PR_CreateProcessDetached(pszPath, (char * const *)args, nsnull, attr) != PR_SUCCESS)
603 goto end;
604
605 // Close /dev/null
606 PR_Close(devNull);
607 // Close the child end of the pipe to make it the only owner of the
608 // file descriptor, so that unexpected closing can be detected.
609 PR_Close(writable);
610 writable = nsnull;
611
612 char msg[10];
613 memset(msg, '\0', sizeof(msg));
614 if ( PR_Read(readable, msg, sizeof(msg)-1) != 5
615 || strcmp(msg, "READY"))
616 goto end;
617
618 rv = NS_OK;
619
620end:
621 if (readable)
622 PR_Close(readable);
623 if (writable)
624 PR_Close(writable);
625 if (attr)
626 PR_DestroyProcessAttr(attr);
627 return rv;
628}
629
630int main(int argc, char **argv)
631{
632 /*
633 * Initialize the VBox runtime without loading
634 * the support driver
635 */
636 int vrc = RTR3InitExe(argc, &argv, 0);
637 if (RT_FAILURE(vrc))
638 return RTMsgInitFailure(vrc);
639
640 static const RTGETOPTDEF s_aOptions[] =
641 {
642 { "--automate", 'a', RTGETOPT_REQ_NOTHING },
643 { "--auto-shutdown", 'A', RTGETOPT_REQ_NOTHING },
644 { "--daemonize", 'd', RTGETOPT_REQ_NOTHING },
645 { "--shutdown-delay", 'D', RTGETOPT_REQ_UINT32 },
646 { "--pidfile", 'p', RTGETOPT_REQ_STRING },
647 { "--logfile", 'F', RTGETOPT_REQ_STRING },
648 { "--logrotate", 'R', RTGETOPT_REQ_UINT32 },
649 { "--logsize", 'S', RTGETOPT_REQ_UINT64 },
650 { "--loginterval", 'I', RTGETOPT_REQ_UINT32 }
651 };
652
653 const char *pszLogFile = NULL;
654 uint32_t cHistory = 10; // enable log rotation, 10 files
655 uint32_t uHistoryFileTime = RT_SEC_1DAY; // max 1 day per file
656 uint64_t uHistoryFileSize = 100 * _1M; // max 100MB per file
657 bool fDaemonize = false;
658 PRFileDesc *daemon_pipe_wr = nsnull;
659
660 RTGETOPTSTATE GetOptState;
661 vrc = RTGetOptInit(&GetOptState, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
662 AssertRC(vrc);
663
664 RTGETOPTUNION ValueUnion;
665 while ((vrc = RTGetOpt(&GetOptState, &ValueUnion)))
666 {
667 switch (vrc)
668 {
669 case 'a':
670 /* --automate mode means we are started by XPCOM on
671 * demand. Daemonize ourselves and activate
672 * auto-shutdown. */
673 gAutoShutdown = true;
674 fDaemonize = true;
675 break;
676
677 case 'A':
678 /* --auto-shutdown mode means we're already daemonized. */
679 gAutoShutdown = true;
680 break;
681
682 case 'd':
683 fDaemonize = true;
684 break;
685
686 case 'D':
687 gShutdownDelayMs = ValueUnion.u32;
688 break;
689
690 case 'p':
691 g_pszPidFile = ValueUnion.psz;
692 break;
693
694 case 'F':
695 pszLogFile = ValueUnion.psz;
696 break;
697
698 case 'R':
699 cHistory = ValueUnion.u32;
700 break;
701
702 case 'S':
703 uHistoryFileSize = ValueUnion.u64;
704 break;
705
706 case 'I':
707 uHistoryFileTime = ValueUnion.u32;
708 break;
709
710 case 'h':
711 RTPrintf("no help\n");
712 return RTEXITCODE_SYNTAX;
713
714 case 'V':
715 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
716 return RTEXITCODE_SUCCESS;
717
718 default:
719 return RTGetOptPrintError(vrc, &ValueUnion);
720 }
721 }
722
723 if (fDaemonize)
724 {
725 vboxsvcSpawnDaemonByReExec(argv[0], gAutoShutdown, g_pszPidFile);
726 exit(126);
727 }
728
729 nsresult rc;
730
731 /** @todo Merge this code with svcmain.cpp (use Logging.cpp?). */
732 char szLogFile[RTPATH_MAX];
733 if (!pszLogFile)
734 {
735 vrc = com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile));
736 if (RT_SUCCESS(vrc))
737 vrc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxSVC.log");
738 }
739 else
740 {
741 if (!RTStrPrintf(szLogFile, sizeof(szLogFile), "%s", pszLogFile))
742 vrc = VERR_NO_MEMORY;
743 }
744 if (RT_FAILURE(vrc))
745 return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to create logging file name, rc=%Rrc", vrc);
746
747 RTERRINFOSTATIC ErrInfo;
748 vrc = com::VBoxLogRelCreate("XPCOM Server", szLogFile,
749 RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG,
750 VBOXSVC_LOG_DEFAULT, "VBOXSVC_RELEASE_LOG",
751 RTLOGDEST_FILE, UINT32_MAX /* cMaxEntriesPerGroup */,
752 cHistory, uHistoryFileTime, uHistoryFileSize,
753 RTErrInfoInitStatic(&ErrInfo));
754 if (RT_FAILURE(vrc))
755 return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open release log (%s, %Rrc)", ErrInfo.Core.pszMsg, vrc);
756
757 /* Set up a build identifier so that it can be seen from core dumps what
758 * exact build was used to produce the core. Same as in Console::i_powerUpThread(). */
759 static char saBuildID[48];
760 RTStrPrintf(saBuildID, sizeof(saBuildID), "%s%s%s%s VirtualBox %s r%u %s%s%s%s",
761 "BU", "IL", "DI", "D", RTBldCfgVersion(), RTBldCfgRevision(), "BU", "IL", "DI", "D");
762
763 daemon_pipe_wr = PR_GetInheritedFD(VBOXSVC_STARTUP_PIPE_NAME);
764 RTEnvUnset("NSPR_INHERIT_FDS");
765
766 const nsModuleComponentInfo VirtualBoxInfo = {
767 "VirtualBox component",
768 NS_VIRTUALBOX_CID,
769 NS_VIRTUALBOX_CONTRACTID,
770 VirtualBoxConstructor, // constructor function
771 NULL, // registration function
772 NULL, // deregistration function
773 VirtualBoxClassFactory::FactoryDestructor, // factory destructor function
774 NS_CI_INTERFACE_GETTER_NAME(VirtualBoxWrap),
775 NULL, // language helper
776 &NS_CLASSINFO_NAME(VirtualBoxWrap),
777 0 // flags
778 };
779
780 const nsModuleComponentInfoPlusFactoryConstructor components[] = {
781 {
782 &VirtualBoxInfo,
783 VirtualBoxClassFactory::FactoryConstructor // factory constructor function
784 }
785 };
786
787 do /* goto avoidance only */
788 {
789 rc = com::Initialize();
790 if (NS_FAILED(rc))
791 {
792 RTMsgError("Failed to initialize XPCOM! (rc=%Rhrc)\n", rc);
793 break;
794 }
795
796 nsCOMPtr<nsIComponentRegistrar> registrar;
797 rc = NS_GetComponentRegistrar(getter_AddRefs(registrar));
798 if (NS_FAILED(rc))
799 {
800 RTMsgError("Failed to get component registrar! (rc=%Rhrc)", rc);
801 break;
802 }
803
804 registrar->AutoRegister(nsnull);
805 rc = RegisterSelfComponents(registrar, components,
806 NS_ARRAY_LENGTH(components));
807 if (NS_FAILED(rc))
808 {
809 RTMsgError("Failed to register server components! (rc=%Rhrc)", rc);
810 break;
811 }
812
813 nsCOMPtr<ipcIService> ipcServ(do_GetService(IPC_SERVICE_CONTRACTID, &rc));
814 if (NS_FAILED(rc))
815 {
816 RTMsgError("Failed to get IPC service! (rc=%Rhrc)", rc);
817 break;
818 }
819
820 NS_ADDREF(gIpcServ = ipcServ);
821
822 LogFlowFunc(("Will use \"%s\" as server name.\n", VBOXSVC_IPC_NAME));
823
824 rc = gIpcServ->AddName(VBOXSVC_IPC_NAME);
825 if (NS_FAILED(rc))
826 {
827 LogFlowFunc(("Failed to register the server name (rc=%Rhrc (%08X))!\n"
828 "Is another server already running?\n", rc, rc));
829
830 RTMsgError("Failed to register the server name \"%s\" (rc=%Rhrc)!\n"
831 "Is another server already running?\n",
832 VBOXSVC_IPC_NAME, rc);
833 NS_RELEASE(gIpcServ);
834 break;
835 }
836
837 {
838 /* setup signal handling to convert some signals to a quit event */
839 struct sigaction sa;
840 sa.sa_handler = signal_handler;
841 sigemptyset(&sa.sa_mask);
842 sa.sa_flags = 0;
843 sigaction(SIGINT, &sa, NULL);
844 sigaction(SIGQUIT, &sa, NULL);
845 sigaction(SIGTERM, &sa, NULL);
846// XXX Temporary allow release assertions to terminate VBoxSVC
847// sigaction(SIGTRAP, &sa, NULL);
848 sigaction(SIGUSR1, &sa, NULL);
849 }
850
851 {
852 char szBuf[80];
853 size_t cSize;
854
855 cSize = RTStrPrintf(szBuf, sizeof(szBuf),
856 VBOX_PRODUCT" XPCOM Server Version "
857 VBOX_VERSION_STRING);
858 for (size_t i = cSize; i > 0; i--)
859 putchar('*');
860 RTPrintf("\n%s\n", szBuf);
861 RTPrintf("(C) 2004-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
862 "All rights reserved.\n");
863#ifdef DEBUG
864 RTPrintf("Debug version.\n");
865#endif
866 }
867
868 if (daemon_pipe_wr != nsnull)
869 {
870 RTPrintf("\nStarting event loop....\n[send TERM signal to quit]\n");
871 /* now we're ready, signal the parent process */
872 PR_Write(daemon_pipe_wr, RT_STR_TUPLE("READY"));
873 /* close writing end of the pipe, its job is done */
874 PR_Close(daemon_pipe_wr);
875 }
876 else
877 RTPrintf("\nStarting event loop....\n[press Ctrl-C to quit]\n");
878
879 if (g_pszPidFile)
880 {
881 RTFILE hPidFile = NIL_RTFILE;
882 vrc = RTFileOpen(&hPidFile, g_pszPidFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE);
883 if (RT_SUCCESS(vrc))
884 {
885 char szBuf[32];
886 const char *lf = "\n";
887 RTStrFormatNumber(szBuf, getpid(), 10, 0, 0, 0);
888 RTFileWrite(hPidFile, szBuf, strlen(szBuf), NULL);
889 RTFileWrite(hPidFile, lf, strlen(lf), NULL);
890 RTFileClose(hPidFile);
891 }
892 }
893
894 // Increase the file table size to 10240 or as high as possible.
895 struct rlimit lim;
896 if (getrlimit(RLIMIT_NOFILE, &lim) == 0)
897 {
898 if ( lim.rlim_cur < 10240
899 && lim.rlim_cur < lim.rlim_max)
900 {
901 lim.rlim_cur = RT_MIN(lim.rlim_max, 10240);
902 if (setrlimit(RLIMIT_NOFILE, &lim) == -1)
903 RTPrintf("WARNING: failed to increase file descriptor limit. (%d)\n", errno);
904 }
905 }
906 else
907 RTPrintf("WARNING: failed to obtain per-process file-descriptor limit (%d).\n", errno);
908
909 /* get the main thread's event queue */
910 gEventQ = com::NativeEventQueue::getMainEventQueue();
911 if (!gEventQ)
912 {
913 RTMsgError("Failed to get the main event queue! (rc=%Rhrc)", rc);
914 break;
915 }
916
917 while (gKeepRunning)
918 {
919 vrc = gEventQ->processEventQueue(RT_INDEFINITE_WAIT);
920 if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
921 {
922 LogRel(("Failed to wait for events! (rc=%Rrc)", vrc));
923 break;
924 }
925 }
926
927 gEventQ = NULL;
928 RTPrintf("Terminated event loop.\n");
929
930 /* unregister ourselves. After this point, clients will start a new
931 * process because they won't be able to resolve the server name.*/
932 gIpcServ->RemoveName(VBOXSVC_IPC_NAME);
933 }
934 while (0); // this scopes the nsCOMPtrs
935
936 NS_IF_RELEASE(gIpcServ);
937
938 /* no nsCOMPtrs are allowed to be alive when you call com::Shutdown(). */
939
940 LogFlowFunc(("Calling com::Shutdown()...\n"));
941 rc = com::Shutdown();
942 LogFlowFunc(("Finished com::Shutdown() (rc=%Rhrc)\n", rc));
943
944 if (NS_FAILED(rc))
945 RTMsgError("Failed to shutdown XPCOM! (rc=%Rhrc)", rc);
946
947 RTPrintf("XPCOM server has shutdown.\n");
948
949 if (g_pszPidFile)
950 RTFileDelete(g_pszPidFile);
951
952 return RTEXITCODE_SUCCESS;
953}
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