1
/* $Id: server.cpp $ */
3
* XPCOM server process (VBoxSVC) start point.
7
* Copyright (C) 2006-2009 Oracle Corporation
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.
18
#include <ipcIService.h>
21
#include <nsIComponentRegistrar.h>
24
# include <nsXPCOMGlue.h>
27
#include <nsEventQueueUtils.h>
28
#include <nsGenericFactory.h>
30
#include "xpcom/server.h"
34
#include <VBox/param.h>
35
#include <VBox/version.h>
37
#include <iprt/buildconfig.h>
38
#include <iprt/initterm.h>
39
#include <iprt/critsect.h>
40
#include <iprt/getopt.h>
41
#include <iprt/message.h>
42
#include <iprt/stream.h>
43
#include <iprt/path.h>
44
#include <iprt/timer.h>
46
#include <signal.h> // for the signal handler
52
#include <sys/resource.h>
54
/////////////////////////////////////////////////////////////////////////////
55
// VirtualBox component instantiation
56
/////////////////////////////////////////////////////////////////////////////
58
#include <nsIGenericFactory.h>
60
#include <VirtualBox_XPCOM.h>
61
#include <VirtualBoxImpl.h>
62
#include <MachineImpl.h>
63
#include <VFSExplorerImpl.h>
64
#include <ApplianceImpl.h>
65
#include <SnapshotImpl.h>
66
#include <MediumImpl.h>
67
#include <MediumFormatImpl.h>
68
#include <ProgressCombinedImpl.h>
69
#include <ProgressProxyImpl.h>
70
#include <VRDPServerImpl.h>
71
#include <SharedFolderImpl.h>
73
#include <HostNetworkInterfaceImpl.h>
74
#include <GuestOSTypeImpl.h>
75
#include <NetworkAdapterImpl.h>
76
#include <NATEngineImpl.h>
77
#include <SerialPortImpl.h>
78
#include <ParallelPortImpl.h>
79
#include <USBControllerImpl.h>
80
#include "DHCPServerRunner.h"
81
#include "DHCPServerImpl.h"
83
# include <HostUSBDeviceImpl.h>
84
# include <USBDeviceImpl.h>
86
#include <StorageControllerImpl.h>
87
#include <AudioAdapterImpl.h>
88
#include <SystemPropertiesImpl.h>
90
/* implement nsISupports parts of our objects with support for nsIClassInfo */
92
NS_DECL_CLASSINFO(VirtualBox)
93
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VirtualBox, IVirtualBox)
95
NS_DECL_CLASSINFO(Machine)
96
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Machine, IMachine)
98
NS_DECL_CLASSINFO(VFSExplorer)
99
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VFSExplorer, IVFSExplorer)
101
NS_DECL_CLASSINFO(Appliance)
102
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Appliance, IAppliance)
104
NS_DECL_CLASSINFO(VirtualSystemDescription)
105
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VirtualSystemDescription, IVirtualSystemDescription)
107
NS_DECL_CLASSINFO(SessionMachine)
108
NS_IMPL_THREADSAFE_ISUPPORTS2_CI(SessionMachine, IMachine, IInternalMachineControl)
110
NS_DECL_CLASSINFO(SnapshotMachine)
111
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SnapshotMachine, IMachine)
113
NS_DECL_CLASSINFO(Snapshot)
114
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Snapshot, ISnapshot)
116
NS_DECL_CLASSINFO(Medium)
117
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Medium, IMedium)
119
NS_DECL_CLASSINFO(MediumFormat)
120
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(MediumFormat, IMediumFormat)
122
NS_DECL_CLASSINFO(MediumAttachment)
123
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(MediumAttachment, IMediumAttachment)
125
NS_DECL_CLASSINFO(Progress)
126
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Progress, IProgress)
128
NS_DECL_CLASSINFO(CombinedProgress)
129
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(CombinedProgress, IProgress)
131
NS_DECL_CLASSINFO(ProgressProxy)
132
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ProgressProxy, IProgress)
134
NS_DECL_CLASSINFO(SharedFolder)
135
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SharedFolder, ISharedFolder)
137
#ifdef VBOX_WITH_VRDP
138
NS_DECL_CLASSINFO(VRDPServer)
139
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VRDPServer, IVRDPServer)
142
NS_DECL_CLASSINFO(Host)
143
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Host, IHost)
145
NS_DECL_CLASSINFO(HostNetworkInterface)
146
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HostNetworkInterface, IHostNetworkInterface)
148
NS_DECL_CLASSINFO(DHCPServer)
149
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(DHCPServer, IDHCPServer)
151
NS_DECL_CLASSINFO(GuestOSType)
152
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestOSType, IGuestOSType)
154
NS_DECL_CLASSINFO(NetworkAdapter)
155
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(NetworkAdapter, INetworkAdapter)
157
NS_DECL_CLASSINFO(NATEngine)
158
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(NATEngine, INATEngine)
161
NS_DECL_CLASSINFO(SerialPort)
162
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SerialPort, ISerialPort)
164
NS_DECL_CLASSINFO(ParallelPort)
165
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ParallelPort, IParallelPort)
167
NS_DECL_CLASSINFO(USBController)
168
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBController, IUSBController)
170
NS_DECL_CLASSINFO(StorageController)
171
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(StorageController, IStorageController)
174
NS_DECL_CLASSINFO(USBDeviceFilter)
175
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBDeviceFilter, IUSBDeviceFilter)
177
NS_DECL_CLASSINFO(HostUSBDevice)
178
NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HostUSBDevice, IUSBDevice, IHostUSBDevice)
180
NS_DECL_CLASSINFO(HostUSBDeviceFilter)
181
NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HostUSBDeviceFilter, IUSBDeviceFilter, IHostUSBDeviceFilter)
184
NS_DECL_CLASSINFO(AudioAdapter)
185
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(AudioAdapter, IAudioAdapter)
187
NS_DECL_CLASSINFO(SystemProperties)
188
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SystemProperties, ISystemProperties)
190
#ifdef VBOX_WITH_RESOURCE_USAGE_API
191
NS_DECL_CLASSINFO(PerformanceCollector)
192
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PerformanceCollector, IPerformanceCollector)
193
NS_DECL_CLASSINFO(PerformanceMetric)
194
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PerformanceMetric, IPerformanceMetric)
195
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
197
NS_DECL_CLASSINFO(BIOSSettings)
198
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(BIOSSettings, IBIOSSettings)
200
////////////////////////////////////////////////////////////////////////////////
204
/* Delay before shutting down the VirtualBox server after the last
205
* VirtualBox instance is released, in ms */
206
VBoxSVC_ShutdownDelay = 5000
209
static bool gAutoShutdown = false;
211
static nsIEventQueue *gEventQ = nsnull;
212
static PRBool volatile gKeepRunning = PR_TRUE;
213
static PRBool volatile gAllowSigUsrQuit = PR_TRUE;
215
/////////////////////////////////////////////////////////////////////////////
218
* Simple but smart PLEvent wrapper.
220
* @note Instances must be always created with <tt>operator new</tt>!
232
* Posts this event to the given message queue. This method may only be
233
* called once. @note On success, the event will be deleted automatically
234
* after it is delivered and handled. On failure, the event will delete
235
* itself before this method returns! The caller must not delete it in
238
nsresult postTo(nsIEventQueue *aEventQ)
240
AssertReturn(mEv.that == NULL, NS_ERROR_FAILURE);
241
AssertReturn(aEventQ, NS_ERROR_FAILURE);
242
nsresult rv = aEventQ->InitEvent(&mEv.e, NULL,
243
eventHandler, eventDestructor);
244
if (NS_SUCCEEDED(rv))
247
rv = aEventQ->PostEvent(&mEv.e);
248
if (NS_SUCCEEDED(rv))
255
virtual void *handler() = 0;
265
static void *PR_CALLBACK eventHandler(PLEvent *self)
267
return reinterpret_cast<Ev *>(self)->that->handler();
270
static void PR_CALLBACK eventDestructor(PLEvent *self)
272
delete reinterpret_cast<Ev *>(self)->that;
276
////////////////////////////////////////////////////////////////////////////////
279
* VirtualBox class factory that destroys the created instance right after
280
* the last reference to it is released by the client, and recreates it again
281
* when necessary (so VirtualBox acts like a singleton object).
283
class VirtualBoxClassFactory : public VirtualBox
287
virtual ~VirtualBoxClassFactory()
289
LogFlowFunc(("Deleting VirtualBox...\n"));
294
LogFlowFunc(("VirtualBox object deleted.\n"));
295
RTPrintf("Informational: VirtualBox object deleted.\n");
298
NS_IMETHOD_(nsrefcnt) Release()
300
/* we overload Release() to guarantee the VirtualBox destructor is
301
* always called on the main thread */
303
nsrefcnt count = VirtualBox::Release();
307
/* the last reference held by clients is being released
308
* (see GetInstance()) */
310
PRBool onMainThread = PR_TRUE;
312
gEventQ->IsOnCurrentThread(&onMainThread);
314
PRBool timerStarted = PR_FALSE;
316
/* sTimer is null if this call originates from FactoryDestructor()*/
319
LogFlowFunc(("Last VirtualBox instance was released.\n"));
320
LogFlowFunc(("Scheduling server shutdown in %d ms...\n",
321
VBoxSVC_ShutdownDelay));
323
/* make sure the previous timer (if any) is stopped;
324
* otherwise RTTimerStart() will definitely fail. */
325
RTTimerLRStop(sTimer);
327
int vrc = RTTimerLRStart(sTimer, uint64_t(VBoxSVC_ShutdownDelay) * 1000000);
329
timerStarted = SUCCEEDED(vrc);
333
LogFlowFunc(("Last VirtualBox instance was released "
334
"on XPCOM shutdown.\n"));
335
Assert(onMainThread);
338
gAllowSigUsrQuit = PR_TRUE;
344
/* Failed to start the timer, post the shutdown event
345
* manually if not on the main thread alreay. */
346
ShutdownTimer(NULL, NULL, 0);
352
* a) gEventQ is 0 which means either FactoryDestructor() is called
353
* or the IPC/DCONNECT shutdown sequence is initiated by the
354
* XPCOM shutdown routine (NS_ShutdownXPCOM()), which always
355
* happens on the main thread.
357
* b) gEventQ has reported we're on the main thread. This means
358
* that DestructEventHandler() has been called, but another
359
* client was faster and requested VirtualBox again.
361
* In either case, there is nothing to do.
363
* Note: case b) is actually no more valid since we don't
364
* call Release() from DestructEventHandler() in this case
365
* any more. Thus, we assert below.
368
Assert(gEventQ == NULL);
376
class MaybeQuitEvent : public MyEvent
378
/* called on the main thread */
383
Assert(RTCritSectIsInitialized(&sLock));
385
/* stop accepting GetInstance() requests on other threads during
386
* possible destruction */
387
RTCritSectEnter(&sLock);
391
/* sInstance is NULL here if it was deleted immediately after
392
* creation due to initialization error. See GetInstance(). */
393
if (sInstance != NULL)
395
/* Release the guard reference added in GetInstance() */
396
count = sInstance->Release();
403
Assert(sInstance == NULL);
404
LogFlowFunc(("Terminating the server process...\n"));
405
/* make it leave the event loop */
406
gKeepRunning = PR_FALSE;
411
/* This condition is quite rare: a new client happened to
412
* connect after this event has been posted to the main queue
413
* but before it started to process it. */
414
LogFlowFunc(("Destruction is canceled (refcnt=%d).\n", count));
417
RTCritSectLeave(&sLock);
423
static void ShutdownTimer(RTTIMERLR hTimerLR, void *pvUser, uint64_t /*iTick*/)
428
/* A "too late" event is theoretically possible if somebody
429
* manually ended the server after a destruction has been scheduled
430
* and this method was so lucky that it got a chance to run before
431
* the timer was killed. */
432
AssertReturnVoid(gEventQ);
434
/* post a quit event to the main queue */
435
MaybeQuitEvent *ev = new MaybeQuitEvent();
436
nsresult rv = ev->postTo(gEventQ);
439
/* A failure above means we've been already stopped (for example
440
* by Ctrl-C). FactoryDestructor() (NS_ShutdownXPCOM())
441
* will do the job. Nothing to do. */
444
static NS_IMETHODIMP FactoryConstructor()
448
/* create a critsect to protect object construction */
449
if (RT_FAILURE(RTCritSectInit(&sLock)))
450
return NS_ERROR_OUT_OF_MEMORY;
452
int vrc = RTTimerLRCreateEx(&sTimer, 0, 0, ShutdownTimer, NULL);
455
LogFlowFunc(("Failed to create a timer! (vrc=%Rrc)\n", vrc));
456
return NS_ERROR_FAILURE;
462
static NS_IMETHODIMP FactoryDestructor()
466
RTTimerLRDestroy(sTimer);
469
RTCritSectDelete(&sLock);
471
if (sInstance != NULL)
473
/* Either posting a destruction event falied for some reason (most
474
* likely, the quit event has been received before the last release),
475
* or the client has terminated abnormally w/o releasing its
476
* VirtualBox instance (so NS_ShutdownXPCOM() is doing a cleanup).
477
* Release the guard reference we added in GetInstance(). */
478
sInstance->Release();
484
static nsresult GetInstance(VirtualBox **inst)
486
LogFlowFunc(("Getting VirtualBox object...\n"));
488
RTCritSectEnter(&sLock);
492
LogFlowFunc(("Process termination requested first. Refusing.\n"));
494
RTCritSectLeave(&sLock);
496
/* this rv is what CreateInstance() on the client side returns
497
* when the server process stops accepting events. Do the same
498
* here. The client wrapper should attempt to start a new process in
499
* response to a failure from us. */
500
return NS_ERROR_ABORT;
505
if (sInstance == NULL)
507
LogFlowFunc (("Creating new VirtualBox object...\n"));
508
sInstance = new VirtualBoxClassFactory();
509
if (sInstance != NULL)
511
/* make an extra AddRef to take the full control
512
* on the VirtualBox destruction (see FinalRelease()) */
515
sInstance->AddRef(); /* protect FinalConstruct() */
516
rv = sInstance->FinalConstruct();
517
RTPrintf("Informational: VirtualBox object created (rc=%Rhrc).\n", rv);
520
/* On failure diring VirtualBox initialization, delete it
521
* immediately on the current thread by releasing all
522
* references in order to properly schedule the server
523
* shutdown. Since the object is fully deleted here, there
524
* is a chance to fix the error and request a new
525
* instantiation before the server terminates. However,
526
* the main reason to maintain the shoutdown delay on
527
* failure is to let the front-end completely fetch error
528
* info from a server-side IVirtualBoxErrorInfo object. */
529
sInstance->Release();
530
sInstance->Release();
531
Assert(sInstance == NULL);
535
/* On success, make sure the previous timer is stopped to
536
* cancel a scheduled server termination (if any). */
537
gAllowSigUsrQuit = PR_FALSE;
538
RTTimerLRStop(sTimer);
543
rv = NS_ERROR_OUT_OF_MEMORY;
548
LogFlowFunc(("Using existing VirtualBox object...\n"));
549
nsrefcnt count = sInstance->AddRef();
554
LogFlowFunc(("Another client has requested a reference to VirtualBox, canceling detruction...\n"));
556
/* make sure the previous timer is stopped */
557
gAllowSigUsrQuit = PR_FALSE;
558
RTTimerLRStop(sTimer);
564
RTCritSectLeave(&sLock);
571
/* Don't be confused that sInstance is of the *ClassFactory type. This is
572
* actually a singleton instance (*ClassFactory inherits the singleton
573
* class; we combined them just for "simplicity" and used "static" for
574
* factory methods. *ClassFactory here is necessary for a couple of extra
577
static VirtualBoxClassFactory *sInstance;
578
static RTCRITSECT sLock;
580
static RTTIMERLR sTimer;
583
VirtualBoxClassFactory *VirtualBoxClassFactory::sInstance = NULL;
584
RTCRITSECT VirtualBoxClassFactory::sLock;
586
RTTIMERLR VirtualBoxClassFactory::sTimer = NIL_RTTIMERLR;
588
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR_WITH_RC(VirtualBox, VirtualBoxClassFactory::GetInstance)
590
////////////////////////////////////////////////////////////////////////////////
592
typedef NSFactoryDestructorProcPtr NSFactoryConsructorProcPtr;
595
* Enhanced module component information structure.
597
* nsModuleComponentInfo lacks the factory construction callback, here we add
598
* it. This callback is called by NS_NewGenericFactoryEx() after a
599
* nsGenericFactory instance is successfully created.
601
struct nsModuleComponentInfoEx : nsModuleComponentInfo
603
nsModuleComponentInfoEx() {}
604
nsModuleComponentInfoEx(int) {}
606
nsModuleComponentInfoEx(
607
const char* aDescription,
609
const char* aContractID,
610
NSConstructorProcPtr aConstructor,
611
NSRegisterSelfProcPtr aRegisterSelfProc,
612
NSUnregisterSelfProcPtr aUnregisterSelfProc,
613
NSFactoryDestructorProcPtr aFactoryDestructor,
614
NSGetInterfacesProcPtr aGetInterfacesProc,
615
NSGetLanguageHelperProcPtr aGetLanguageHelperProc,
616
nsIClassInfo ** aClassInfoGlobal,
618
NSFactoryConsructorProcPtr aFactoryConstructor)
620
mDescription = aDescription;
622
mContractID = aContractID;
623
mConstructor = aConstructor;
624
mRegisterSelfProc = aRegisterSelfProc;
625
mUnregisterSelfProc = aUnregisterSelfProc;
626
mFactoryDestructor = aFactoryDestructor;
627
mGetInterfacesProc = aGetInterfacesProc;
628
mGetLanguageHelperProc = aGetLanguageHelperProc;
629
mClassInfoGlobal = aClassInfoGlobal;
631
mFactoryConstructor = aFactoryConstructor;
634
/** (optional) Factory Construction Callback */
635
NSFactoryConsructorProcPtr mFactoryConstructor;
638
////////////////////////////////////////////////////////////////////////////////
640
static const nsModuleComponentInfoEx components[] =
642
nsModuleComponentInfoEx(
643
"VirtualBox component",
644
(nsCID) NS_VIRTUALBOX_CID,
645
NS_VIRTUALBOX_CONTRACTID,
646
VirtualBoxConstructor, // constructor funcion
647
NULL, // registration function
648
NULL, // deregistration function
649
VirtualBoxClassFactory::FactoryDestructor, // factory destructor function
650
NS_CI_INTERFACE_GETTER_NAME(VirtualBox),
651
NULL, // language helper
652
&NS_CLASSINFO_NAME(VirtualBox),
654
VirtualBoxClassFactory::FactoryConstructor // factory constructor function
658
/////////////////////////////////////////////////////////////////////////////
661
* Extends NS_NewGenericFactory() by immediately calling
662
* nsModuleComponentInfoEx::mFactoryConstructor before returning to the
666
NS_NewGenericFactoryEx(nsIGenericFactory **result,
667
const nsModuleComponentInfoEx *info)
669
AssertReturn(result, NS_ERROR_INVALID_POINTER);
671
nsresult rv = NS_NewGenericFactory(result, info);
672
if (NS_SUCCEEDED(rv) && info && info->mFactoryConstructor)
674
rv = info->mFactoryConstructor();
682
/////////////////////////////////////////////////////////////////////////////
685
* Helper function to register self components upon start-up
686
* of the out-of-proc server.
689
RegisterSelfComponents(nsIComponentRegistrar *registrar,
690
const nsModuleComponentInfoEx *aComponents,
694
const nsModuleComponentInfoEx *info = aComponents;
695
for (PRUint32 i = 0; i < count && NS_SUCCEEDED(rc); i++, info++)
697
/* skip components w/o a constructor */
698
if (!info->mConstructor)
700
/* create a new generic factory for a component and register it */
701
nsIGenericFactory *factory;
702
rc = NS_NewGenericFactoryEx(&factory, info);
703
if (NS_SUCCEEDED(rc))
705
rc = registrar->RegisterFactory(info->mCID,
715
/////////////////////////////////////////////////////////////////////////////
717
static ipcIService *gIpcServ = nsnull;
718
static const char *g_pszPidFile = NULL;
720
class ForceQuitEvent : public MyEvent
726
gKeepRunning = PR_FALSE;
729
RTFileDelete(g_pszPidFile);
735
static void signal_handler(int sig)
737
if (gEventQ && gKeepRunning)
741
if (gAllowSigUsrQuit)
743
VirtualBoxClassFactory::MaybeQuitEvent *ev = new VirtualBoxClassFactory::MaybeQuitEvent();
746
/* else do nothing */
750
/* post a force quit event to the queue */
751
ForceQuitEvent *ev = new ForceQuitEvent();
757
int main(int argc, char **argv)
760
* Initialize the VBox runtime without loading
765
static const RTGETOPTDEF s_aOptions[] =
767
{ "--automate", 'a', RTGETOPT_REQ_NOTHING },
768
{ "--auto-shutdown", 'A', RTGETOPT_REQ_NOTHING },
769
{ "--daemonize", 'd', RTGETOPT_REQ_NOTHING },
770
{ "--pidfile", 'p', RTGETOPT_REQ_STRING },
771
{ "--pipe", 'P', RTGETOPT_REQ_UINT32 },
774
bool fDaemonize = false;
775
int daemon_pipe_wr = -1;
777
RTGETOPTSTATE GetOptState;
778
int vrc = RTGetOptInit(&GetOptState, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
781
RTGETOPTUNION ValueUnion;
782
while ((vrc = RTGetOpt(&GetOptState, &ValueUnion)))
788
/* --automate mode means we are started by XPCOM on
789
* demand. Daemonize ourselves and activate
791
gAutoShutdown = true;
796
/* Used together with '-P', see below. Internal use only. */
799
gAutoShutdown = true;
811
g_pszPidFile = ValueUnion.psz;
815
/* This is just an internal hack for passing the pipe write fd
816
along to the final child. Internal use only. */
819
daemon_pipe_wr = ValueUnion.u32;
825
RTPrintf("no help\n");
831
RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
836
return RTGetOptPrintError(vrc, &ValueUnion);
840
#ifdef RT_OS_OS2 /** @todo There is almost no need to make a special case of OS/2 here. Just the execv call needs to be told to create a background process... */
842
/* nothing to do here, the process is supposed to be already
843
* started daemonized when it is necessary */
850
/* create a pipe for communication between child and parent */
851
int daemon_pipe_fds[2] = {-1, -1};
852
if (pipe(daemon_pipe_fds) < 0)
854
RTMsgError("pipe() failed (errno = %d)", errno);
857
daemon_pipe_wr = daemon_pipe_fds[1];
858
int daemon_pipe_rd = daemon_pipe_fds[0];
860
pid_t childpid = fork();
863
RTMsgError("fork() failed (errno = %d)", errno);
869
/* we're the parent process */
870
bool fSuccess = false;
872
/* close the writing end of the pipe */
873
close(daemon_pipe_wr);
875
/* try to read a message from the pipe */
877
RT_ZERO(msg); /* initialize so it's NULL terminated */
878
if (read(daemon_pipe_rd, msg, sizeof(msg) - 1) > 0)
880
if (strcmp(msg, "READY") == 0)
883
RTMsgError("Unknown message from child process (%s)", msg);
886
RTMsgError("0 bytes read from child process");
888
/* close the reading end of the pipe as well and exit */
889
close(daemon_pipe_rd);
890
return fSuccess ? 0 : 1;
892
/* we're the child process */
894
/* Create a new SID for the child process */
895
pid_t sid = setsid();
898
RTMsgError("setsid() failed (errno = %d)", errno);
902
/* Need to do another for to get rid of the session leader status.
903
* Otherwise any accidentally opened tty will automatically become a
904
* controlling tty for the daemon process. */
908
RTMsgError("second fork() failed (errno = %d)", errno);
914
/* we're the parent process, just a dummy so terminate now */
918
/* Close all file handles except for the write end of the pipe. */
921
if (getrlimit(RLIMIT_NOFILE, &lim) == 0)
922
fdMax = (int)RT_MIN(lim.rlim_cur, 65535); /* paranoia */
925
for (int fd = 0; fd < fdMax; fd++)
926
if (fd != daemon_pipe_wr)
929
/* Make sure the pipe isn't any of the standard handles. */
930
if (daemon_pipe_wr <= 2)
932
if (dup2(daemon_pipe_wr, 3) == 3)
934
close(daemon_pipe_wr);
939
/* Redirect the standard handles to NULL by opening /dev/null three times. */
940
open("/dev/null", O_RDWR, 0);
941
open("/dev/null", O_RDWR, 0);
942
open("/dev/null", O_RDWR, 0);
945
* On leopard we're no longer allowed to use some of the core API's
946
* after forking - this will cause us to hit an int3.
947
* So, we'll have to execv VBoxSVC once again and hand it the pipe
948
* and all other relevant options.
950
* On FreeBSD the fork approach doesn't work. The child fails
951
* during initialization of XPCOM for some unknown reason and
952
* exits making it impossible to autostart VBoxSVC when starting
953
* a frontend (debugger and strace don't contain any useful info).
955
const char *apszArgs[7 + 2];
957
apszArgs[i++] = argv[0];
958
apszArgs[i++] = "--pipe";
960
RTStrPrintf(szPipeArg, sizeof(szPipeArg), "%d", daemon_pipe_wr);
961
apszArgs[i++] = szPipeArg;
964
apszArgs[i++] = "--pidfile";
965
apszArgs[i++] = g_pszPidFile;
968
apszArgs[i++] = "--auto-shutdown";
969
apszArgs[i++] = NULL; Assert(i <= RT_ELEMENTS(apszArgs));
970
execv(apszArgs[0], (char * const *)apszArgs);
980
rc = com::Initialize();
983
RTMsgError("Failed to initialize XPCOM! (rc=%Rhrc)\n", rc);
987
nsCOMPtr <nsIComponentRegistrar> registrar;
988
rc = NS_GetComponentRegistrar(getter_AddRefs(registrar));
991
RTMsgError("Failed to get component registrar! (rc=%Rhrc)", rc);
995
registrar->AutoRegister(nsnull);
996
rc = RegisterSelfComponents(registrar, components,
997
NS_ARRAY_LENGTH (components));
1000
RTMsgError("Failed to register server components! (rc=%Rhrc)", rc);
1004
/* get the main thread's event queue (afaik, the dconnect service always
1005
* gets created upon XPCOM startup, so it will use the main (this)
1006
* thread's event queue to receive IPC events) */
1007
rc = NS_GetMainEventQ(&gEventQ);
1010
RTMsgError("Failed to get the main event queue! (rc=%Rhrc)", rc);
1014
nsCOMPtr<ipcIService> ipcServ (do_GetService(IPC_SERVICE_CONTRACTID, &rc));
1017
RTMsgError("Failed to get IPC service! (rc=%Rhrc)", rc);
1021
NS_ADDREF(gIpcServ = ipcServ);
1023
LogFlowFunc(("Will use \"%s\" as server name.\n", VBOXSVC_IPC_NAME));
1025
rc = gIpcServ->AddName(VBOXSVC_IPC_NAME);
1028
LogFlowFunc(("Failed to register the server name (rc=%Rhrc (%08X))!\n"
1029
"Is another server already running?\n", rc, rc));
1031
RTMsgError("Failed to register the server name \"%s\" (rc=%Rhrc)!\n"
1032
"Is another server already running?\n",
1033
VBOXSVC_IPC_NAME, rc);
1034
NS_RELEASE(gIpcServ);
1039
/* setup signal handling to convert some signals to a quit event */
1040
struct sigaction sa;
1041
sa.sa_handler = signal_handler;
1042
sigemptyset(&sa.sa_mask);
1044
sigaction(SIGINT, &sa, NULL);
1045
sigaction(SIGQUIT, &sa, NULL);
1046
sigaction(SIGTERM, &sa, NULL);
1047
sigaction(SIGTRAP, &sa, NULL);
1048
sigaction(SIGUSR1, &sa, NULL);
1055
iSize = RTStrPrintf(szBuf, sizeof(szBuf),
1056
VBOX_PRODUCT" XPCOM Server Version "
1057
VBOX_VERSION_STRING);
1058
for (int i = iSize; i > 0; i--)
1060
RTPrintf("\n%s\n", szBuf);
1061
RTPrintf("(C) 2008-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
1062
"All rights reserved.\n");
1064
RTPrintf("Debug version.\n");
1068
if (daemon_pipe_wr >= 0)
1070
RTPrintf("\nStarting event loop....\n[send TERM signal to quit]\n");
1071
/* now we're ready, signal the parent process */
1072
write(daemon_pipe_wr, "READY", strlen("READY"));
1075
RTPrintf("\nStarting event loop....\n[press Ctrl-C to quit]\n");
1079
RTFILE hPidFile = NIL_RTFILE;
1080
vrc = RTFileOpen(&hPidFile, g_pszPidFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE);
1081
if (RT_SUCCESS(vrc))
1084
const char *lf = "\n";
1085
RTStrFormatNumber(szBuf, getpid(), 10, 0, 0, 0);
1086
RTFileWrite(hPidFile, szBuf, strlen(szBuf), NULL);
1087
RTFileWrite(hPidFile, lf, strlen(lf), NULL);
1088
RTFileClose(hPidFile);
1092
// Increase the file table size to 10240 or as high as possible.
1094
if (getrlimit(RLIMIT_NOFILE, &lim) == 0)
1096
if ( lim.rlim_cur < 10240
1097
&& lim.rlim_cur < lim.rlim_max)
1099
lim.rlim_cur = RT_MIN(lim.rlim_max, 10240);
1100
if (setrlimit(RLIMIT_NOFILE, &lim) == -1)
1101
RTPrintf("WARNING: failed to increase file descriptor limit. (%d)\n", errno);
1105
RTPrintf("WARNING: failed to obtain per-process file-descriptor limit (%d).\n", errno);
1108
while (gKeepRunning)
1110
gEventQ->WaitForEvent(&ev);
1111
gEventQ->HandleEvent(ev);
1114
/* stop accepting new events. Clients that happen to resolve our
1115
* name and issue a CreateInstance() request after this point will
1116
* get NS_ERROR_ABORT once we hande the remaining messages. As a
1117
* result, they should try to start a new server process. */
1118
gEventQ->StopAcceptingEvents();
1120
/* unregister ourselves. After this point, clients will start a new
1121
* process because they won't be able to resolve the server name.*/
1122
gIpcServ->RemoveName(VBOXSVC_IPC_NAME);
1124
/* process any remaining events. These events may include
1125
* CreateInstance() requests received right before we called
1126
* StopAcceptingEvents() above. We will detect this case below,
1127
* restore gKeepRunning and continue to serve. */
1128
gEventQ->ProcessPendingEvents();
1130
RTPrintf("Terminated event loop.\n");
1132
while (0); // this scopes the nsCOMPtrs
1134
NS_IF_RELEASE(gIpcServ);
1135
NS_IF_RELEASE(gEventQ);
1137
/* no nsCOMPtrs are allowed to be alive when you call com::Shutdown(). */
1139
LogFlowFunc(("Calling com::Shutdown()...\n"));
1140
rc = com::Shutdown();
1141
LogFlowFunc(("Finished com::Shutdown() (rc=%Rhrc)\n", rc));
1144
RTMsgError("Failed to shutdown XPCOM! (rc=%Rhrc)", rc);
1146
RTPrintf("XPCOM server has shutdown.\n");
1149
RTFileDelete(g_pszPidFile);
1151
/* close writing end of the pipe as well */
1152
if (daemon_pipe_wr >= 0)
1153
close(daemon_pipe_wr);