VirtualBox

source: vbox/trunk/src/VBox/Main/linux/server.cpp@ 6826

Last change on this file since 6826 was 6826, checked in by vboxsync, 17 years ago

Fixed the lingering VBoxSVC process on darwin.

The daemonize fix for darwin didn't pass down the gAutoShutdown
option. Added anoter internal flag -A / --auto-shutdown option
to convey this across execv.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.0 KB
Line 
1/** @file
2 *
3 * XPCOM server process start point
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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#include <ipcIService.h>
19#include <ipcCID.h>
20
21#include <nsIComponentRegistrar.h>
22
23#if defined(XPCOM_GLUE)
24#include <nsXPCOMGlue.h>
25#endif
26
27#include <nsEventQueueUtils.h>
28#include <nsGenericFactory.h>
29
30#include "linux/server.h"
31
32#include "Logging.h"
33
34#include <iprt/runtime.h>
35#include <iprt/path.h>
36#include <iprt/critsect.h>
37#include <iprt/timer.h>
38
39#include <VBox/param.h>
40#include <VBox/version.h>
41
42#include <VBox/com/com.h>
43
44#include <stdio.h>
45
46// for the signal handler
47#include <signal.h>
48#include <stdlib.h>
49#include <unistd.h>
50#include <errno.h>
51#include <getopt.h>
52
53// for the backtrace signal handler
54#if defined(DEBUG) && defined(RT_OS_LINUX)
55# define USE_BACKTRACE
56#endif
57#if defined(USE_BACKTRACE)
58# include <execinfo.h>
59// get REG_EIP/RIP from ucontext.h
60# ifndef __USE_GNU
61# define __USE_GNU
62# endif
63# include <ucontext.h>
64# ifdef RT_ARCH_AMD64
65# define REG_PC REG_RIP
66# else
67# define REG_PC REG_EIP
68# endif
69#endif
70
71/////////////////////////////////////////////////////////////////////////////
72// VirtualBox component instantiation
73/////////////////////////////////////////////////////////////////////////////
74
75#include <nsIGenericFactory.h>
76
77#include <VirtualBox_XPCOM.h>
78#include <VirtualBoxImpl.h>
79#include <MachineImpl.h>
80#include <SnapshotImpl.h>
81#include <HardDiskImpl.h>
82#include <ProgressImpl.h>
83#include <DVDDriveImpl.h>
84#include <FloppyDriveImpl.h>
85#include <VRDPServerImpl.h>
86#include <DVDImageImpl.h>
87#include <FloppyImageImpl.h>
88#include <SharedFolderImpl.h>
89#include <HostImpl.h>
90#include <HostDVDDriveImpl.h>
91#include <HostFloppyDriveImpl.h>
92#include <HostUSBDeviceImpl.h>
93#include <GuestOSTypeImpl.h>
94#include <NetworkAdapterImpl.h>
95#include <SerialPortImpl.h>
96#include <ParallelPortImpl.h>
97#include <USBControllerImpl.h>
98#include <USBDeviceImpl.h>
99#include <AudioAdapterImpl.h>
100#include <SystemPropertiesImpl.h>
101#include <Collection.h>
102
103// implement nsISupports parts of our objects with support for nsIClassInfo
104NS_DECL_CLASSINFO(VirtualBox)
105NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VirtualBox, IVirtualBox)
106NS_DECL_CLASSINFO(Machine)
107NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Machine, IMachine)
108NS_DECL_CLASSINFO(SessionMachine)
109NS_IMPL_THREADSAFE_ISUPPORTS2_CI(SessionMachine, IMachine, IInternalMachineControl)
110NS_DECL_CLASSINFO(SnapshotMachine)
111NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SnapshotMachine, IMachine)
112NS_DECL_CLASSINFO(Snapshot)
113NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Snapshot, ISnapshot)
114NS_DECL_CLASSINFO(HardDisk)
115NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HardDisk, IHardDisk)
116NS_DECL_CLASSINFO(HVirtualDiskImage)
117NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HVirtualDiskImage, IHardDisk, IVirtualDiskImage)
118NS_DECL_CLASSINFO(HISCSIHardDisk)
119NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HISCSIHardDisk, IHardDisk, IISCSIHardDisk)
120NS_DECL_CLASSINFO(HVMDKImage)
121NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HVMDKImage, IHardDisk, IVMDKImage)
122NS_DECL_CLASSINFO(HCustomHardDisk)
123NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HCustomHardDisk, IHardDisk, ICustomHardDisk)
124NS_DECL_CLASSINFO(HVHDImage)
125NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HVHDImage, IHardDisk, IVHDImage)
126NS_DECL_CLASSINFO(HardDiskAttachment)
127NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HardDiskAttachment, IHardDiskAttachment)
128NS_DECL_CLASSINFO(Progress)
129NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Progress, IProgress)
130NS_DECL_CLASSINFO(CombinedProgress)
131NS_IMPL_THREADSAFE_ISUPPORTS1_CI(CombinedProgress, IProgress)
132NS_DECL_CLASSINFO(DVDDrive)
133NS_IMPL_THREADSAFE_ISUPPORTS1_CI(DVDDrive, IDVDDrive)
134NS_DECL_CLASSINFO(FloppyDrive)
135NS_IMPL_THREADSAFE_ISUPPORTS1_CI(FloppyDrive, IFloppyDrive)
136NS_DECL_CLASSINFO(SharedFolder)
137NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SharedFolder, ISharedFolder)
138#ifdef VBOX_VRDP
139NS_DECL_CLASSINFO(VRDPServer)
140NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VRDPServer, IVRDPServer)
141#endif
142NS_DECL_CLASSINFO(DVDImage)
143NS_IMPL_THREADSAFE_ISUPPORTS1_CI(DVDImage, IDVDImage)
144NS_DECL_CLASSINFO(FloppyImage)
145NS_IMPL_THREADSAFE_ISUPPORTS1_CI(FloppyImage, IFloppyImage)
146NS_DECL_CLASSINFO(Host)
147NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Host, IHost)
148NS_DECL_CLASSINFO(HostDVDDrive)
149NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HostDVDDrive, IHostDVDDrive)
150NS_DECL_CLASSINFO(HostFloppyDrive)
151NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HostFloppyDrive, IHostFloppyDrive)
152NS_DECL_CLASSINFO(GuestOSType)
153NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestOSType, IGuestOSType)
154NS_DECL_CLASSINFO(NetworkAdapter)
155NS_IMPL_THREADSAFE_ISUPPORTS1_CI(NetworkAdapter, INetworkAdapter)
156NS_DECL_CLASSINFO(SerialPort)
157NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SerialPort, ISerialPort)
158NS_DECL_CLASSINFO(ParallelPort)
159NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ParallelPort, IParallelPort)
160NS_DECL_CLASSINFO(USBController)
161NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBController, IUSBController)
162NS_DECL_CLASSINFO(USBDeviceFilter)
163NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBDeviceFilter, IUSBDeviceFilter)
164NS_DECL_CLASSINFO(HostUSBDevice)
165NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HostUSBDevice, IUSBDevice, IHostUSBDevice)
166NS_DECL_CLASSINFO(HostUSBDeviceFilter)
167NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HostUSBDeviceFilter, IUSBDeviceFilter, IHostUSBDeviceFilter)
168NS_DECL_CLASSINFO(AudioAdapter)
169NS_IMPL_THREADSAFE_ISUPPORTS1_CI(AudioAdapter, IAudioAdapter)
170NS_DECL_CLASSINFO(SystemProperties)
171NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SystemProperties, ISystemProperties)
172NS_DECL_CLASSINFO(BIOSSettings)
173NS_IMPL_THREADSAFE_ISUPPORTS1_CI(BIOSSettings, IBIOSSettings)
174
175// collections and enumerators
176COM_IMPL_READONLY_ENUM_AND_COLLECTION(Machine)
177COM_IMPL_READONLY_ENUM_AND_COLLECTION(Snapshot)
178COM_IMPL_READONLY_ENUM_AND_COLLECTION(HardDiskAttachment)
179COM_IMPL_READONLY_ENUM_AND_COLLECTION(GuestOSType)
180COM_IMPL_READONLY_ENUM_AND_COLLECTION(USBDeviceFilter)
181COM_IMPL_READONLY_ENUM_AND_COLLECTION(HostDVDDrive)
182COM_IMPL_READONLY_ENUM_AND_COLLECTION(HostFloppyDrive)
183COM_IMPL_READONLY_ENUM_AND_COLLECTION(HostUSBDevice)
184COM_IMPL_READONLY_ENUM_AND_COLLECTION(HostUSBDeviceFilter)
185COM_IMPL_READONLY_ENUM_AND_COLLECTION(HardDisk)
186COM_IMPL_READONLY_ENUM_AND_COLLECTION(DVDImage)
187COM_IMPL_READONLY_ENUM_AND_COLLECTION(FloppyImage)
188COM_IMPL_READONLY_ENUM_AND_COLLECTION(SharedFolder)
189
190COM_IMPL_READONLY_ENUM_AND_COLLECTION_AS(Progress, IProgress)
191COM_IMPL_READONLY_ENUM_AND_COLLECTION_AS(IfaceUSBDevice, IUSBDevice)
192
193////////////////////////////////////////////////////////////////////////////////
194
195enum
196{
197 /* Delay before shutting down the VirtualBox server after the last
198 * VirtualBox instance is released, in ms */
199 VBoxSVC_ShutdownDelay = 5000,
200};
201
202static bool gAutoShutdown = false;
203
204static nsIEventQueue* gEventQ = nsnull;
205static PRBool volatile gKeepRunning = PR_TRUE;
206
207/////////////////////////////////////////////////////////////////////////////
208
209/**
210 * Simple but smart PLEvent wrapper.
211 *
212 * @note Instances must be always created with <tt>operator new</tt>!
213 */
214class MyEvent
215{
216public:
217
218 MyEvent()
219 {
220 mEv.that = NULL;
221 };
222
223 /**
224 * Posts this event to the given message queue. This method may only be
225 * called once. @note On success, the event will be deleted automatically
226 * after it is delivered and handled. On failure, the event will delete
227 * itself before this method returns! The caller must not delete it in
228 * either case.
229 */
230 nsresult postTo (nsIEventQueue *aEventQ)
231 {
232 AssertReturn (mEv.that == NULL, NS_ERROR_FAILURE);
233 AssertReturn (aEventQ, NS_ERROR_FAILURE);
234 nsresult rv = aEventQ->InitEvent (&mEv.e, NULL,
235 eventHandler, eventDestructor);
236 if (NS_SUCCEEDED (rv))
237 {
238 mEv.that = this;
239 rv = aEventQ->PostEvent (&mEv.e);
240 if (NS_SUCCEEDED (rv))
241 return rv;
242 }
243 delete this;
244 return rv;
245 }
246
247 virtual void *handler() = 0;
248
249private:
250
251 struct Ev
252 {
253 PLEvent e;
254 MyEvent *that;
255 } mEv;
256
257 static void *PR_CALLBACK eventHandler (PLEvent *self)
258 {
259 return reinterpret_cast <Ev *> (self)->that->handler();
260 }
261
262 static void PR_CALLBACK eventDestructor (PLEvent *self)
263 {
264 delete reinterpret_cast <Ev *> (self)->that;
265 }
266};
267
268////////////////////////////////////////////////////////////////////////////////
269
270/**
271 * VirtualBox class factory that destroys the created instance right after
272 * the last reference to it is released by the client, and recreates it again
273 * when necessary (so VirtualBox acts like a singleton object).
274 */
275class VirtualBoxClassFactory : public VirtualBox
276{
277public:
278
279 virtual ~VirtualBoxClassFactory()
280 {
281 LogFlowFunc (("Deleting VirtualBox...\n"));
282
283 FinalRelease();
284 sInstance = 0;
285
286 LogFlowFunc (("VirtualBox object deleted.\n"));
287 printf ("Informational: VirtualBox object deleted.\n");
288 }
289
290 NS_IMETHOD_(nsrefcnt) Release()
291 {
292 /* we overload Release() to guarantee the VirtualBox destructor is
293 * always called on the main thread */
294
295 nsrefcnt count = VirtualBox::Release();
296
297 if (count == 1)
298 {
299 /* the last reference held by clients is being released
300 * (see GetInstance()) */
301
302 PRBool onMainThread = PR_TRUE;
303 if (gEventQ)
304 gEventQ->IsOnCurrentThread (&onMainThread);
305
306 PRBool timerStarted = PR_FALSE;
307
308 /* sTimes is null if this call originates from
309 * FactoryDestructor() */
310 if (sTimer != NULL)
311 {
312 LogFlowFunc (("Last VirtualBox instance was released.\n"));
313 LogFlowFunc (("Scheduling server shutdown in %d ms...\n",
314 VBoxSVC_ShutdownDelay));
315
316 /* make sure the previous timer (if any) is stopped;
317 * otherwise RTTimerStart() will definitely fail. */
318 RTTimerStop (sTimer);
319
320 int vrc = RTTimerStart (sTimer, uint64_t (VBoxSVC_ShutdownDelay) * 1000000);
321 AssertRC (vrc);
322 timerStarted = SUCCEEDED (vrc);
323 }
324 else
325 {
326 LogFlowFunc (("Last VirtualBox instance was released "
327 "on XPCOM shutdown.\n"));
328 Assert (onMainThread);
329 }
330
331 if (!timerStarted)
332 {
333 if (!onMainThread)
334 {
335 /* Failed to start the timer, post the shutdown event
336 * manually if not on the main thread alreay. */
337 ShutdownTimer (NULL, NULL);
338 }
339 else
340 {
341 /* Here we come if:
342 *
343 * a) gEventQ is 0 which means either FactoryDestructor() is called
344 * or the IPC/DCONNECT shutdown sequence is initiated by the
345 * XPCOM shutdown routine (NS_ShutdownXPCOM()), which always
346 * happens on the main thread.
347 *
348 * b) gEventQ has reported we're on the main thread. This means
349 * that DestructEventHandler() has been called, but another
350 * client was faster and requested VirtualBox again.
351 *
352 * In either case, there is nothing to do.
353 *
354 * Note: case b) is actually no more valid since we don't
355 * call Release() from DestructEventHandler() in this case
356 * any more. Thus, we assert below.
357 */
358
359 Assert (gEventQ == NULL);
360 }
361 }
362 }
363
364 return count;
365 }
366
367 class MaybeQuitEvent : public MyEvent
368 {
369 /* called on the main thread */
370 void *handler()
371 {
372 LogFlowFunc (("\n"));
373
374 Assert (RTCritSectIsInitialized (&sLock));
375
376 /* stop accepting GetInstance() requests on other threads during
377 * possible destruction */
378 RTCritSectEnter (&sLock);
379
380 nsrefcnt count = 0;
381
382 /* sInstance is NULL here if it was deleted immediately after
383 * creation due to initialization error. See GetInstance(). */
384 if (sInstance != NULL)
385 {
386 /* Release the guard reference added in GetInstance() */
387 count = sInstance->Release();
388 }
389
390 if (count == 0)
391 {
392 if (gAutoShutdown)
393 {
394 Assert (sInstance == NULL);
395 LogFlowFunc (("Terminating the server process...\n"));
396 /* make it leave the event loop */
397 gKeepRunning = PR_FALSE;
398 }
399 }
400 else
401 {
402 /* This condition is quite rare: a new client will have to
403 * connect after this event has been posted to the main queue
404 * but before it started to process it. */
405 LogFlowFunc (("Destruction is canceled (refcnt=%d).\n", count));
406 }
407
408 RTCritSectLeave (&sLock);
409
410 return NULL;
411 }
412 };
413
414 static void ShutdownTimer (PRTTIMER pTimer, void *pvUser)
415 {
416 NOREF (pTimer);
417 NOREF (pvUser);
418
419 /* A "too late" event is theoretically possible if somebody
420 * manually ended the server after a destruction has been scheduled
421 * and this method was so lucky that it got a chance to run before
422 * the timer was killed. */
423 AssertReturnVoid (gEventQ);
424
425 /* post a quit event to the main queue */
426 MaybeQuitEvent *ev = new MaybeQuitEvent();
427 nsresult rv = ev->postTo (gEventQ);
428 NOREF (rv);
429
430 /* A failure above means we've been already stopped (for example
431 * by Ctrl-C). FactoryDestructor() (NS_ShutdownXPCOM())
432 * will do the job. Nothing to do. */
433 }
434
435 static NS_IMETHODIMP FactoryConstructor()
436 {
437 LogFlowFunc (("\n"));
438
439 /* create a critsect to protect object construction */
440 if (VBOX_FAILURE (RTCritSectInit (&sLock)))
441 return NS_ERROR_OUT_OF_MEMORY;
442
443 int vrc = RTTimerCreateEx (&sTimer, 0, 0, ShutdownTimer, NULL);
444 if (VBOX_FAILURE (vrc))
445 {
446 LogFlowFunc (("Failed to create a timer! (vrc=%Vrc)\n", vrc));
447 return NS_ERROR_FAILURE;
448 }
449
450 return NS_OK;
451 }
452
453 static NS_IMETHODIMP FactoryDestructor()
454 {
455 LogFlowFunc (("\n"));
456
457 RTTimerDestroy (sTimer);
458 sTimer = NULL;
459
460 RTCritSectDelete (&sLock);
461
462 if (sInstance)
463 {
464 /* Either posting a destruction event falied for some reason (most
465 * likely, the quit event has been received before the last release),
466 * or the client has terminated abnormally w/o releasing its
467 * VirtualBox instance (so NS_ShutdownXPCOM() is doing a cleanup).
468 * Release the guard reference we added in GetInstance(). */
469 sInstance->Release();
470 }
471
472 return NS_OK;
473 }
474
475 static nsresult GetInstance (VirtualBox **inst)
476 {
477 LogFlowFunc (("Getting VirtualBox object...\n"));
478
479 RTCritSectEnter (&sLock);
480
481 int rv = NS_OK;
482
483 if (sInstance == 0)
484 {
485 LogFlowFunc (("Creating new VirtualBox object...\n"));
486 sInstance = new VirtualBoxClassFactory();
487 if (sInstance)
488 {
489 /* make an extra AddRef to take the full control
490 * on the VirtualBox destruction (see FinalRelease()) */
491 sInstance->AddRef();
492
493 sInstance->AddRef(); /* protect FinalConstruct() */
494 rv = sInstance->FinalConstruct();
495 printf ("Informational: VirtualBox object created (rc=%08X).\n", rv);
496 if (NS_FAILED (rv))
497 {
498 /* On failure diring VirtualBox initialization, delete it
499 * immediately on the current thread by releasing all
500 * references in order to properly schedule the server
501 * shutdown. Since the object is fully deleted here, there
502 * is a chance to fix the error and request a new
503 * instantiation before the server terminates. However,
504 * the main reason to maintain the shoutdown delay on
505 * failure is to let the front-end completely fetch error
506 * info from a server-side IVirtualBoxErrorInfo object. */
507 sInstance->Release();
508 sInstance->Release();
509 Assert (sInstance == 0);
510 }
511 else
512 {
513 /* On success, make sure the previous timer is stopped to
514 * cancel a scheduled server termination (if any). */
515 RTTimerStop (sTimer);
516 }
517 }
518 else
519 {
520 rv = NS_ERROR_OUT_OF_MEMORY;
521 }
522 }
523 else
524 {
525 LogFlowFunc (("Using existing VirtualBox object...\n"));
526 nsrefcnt count = sInstance->AddRef();
527 Assert (count > 1);
528
529 if (count == 2)
530 {
531 LogFlowFunc (("Another client has requested a reference to VirtualBox, "
532 "canceling detruction...\n"));
533
534 /* make sure the previous timer is stopped */
535 RTTimerStop (sTimer);
536 }
537 }
538
539 *inst = sInstance;
540
541 RTCritSectLeave (&sLock);
542
543 return rv;
544 }
545
546private:
547
548 /* Don't be confused that sInstance is of the *ClassFactory type. This is
549 * actually a singleton instance (*ClassFactory inherits the singleton
550 * class; we combined them just for "simplicity" and used "static" for
551 * factory methods. *ClassFactory here is necessary for a couple of extra
552 * methods. */
553
554 static VirtualBoxClassFactory *sInstance;
555 static RTCRITSECT sLock;
556
557 static PRTTIMER sTimer;
558};
559
560VirtualBoxClassFactory *VirtualBoxClassFactory::sInstance = 0;
561RTCRITSECT VirtualBoxClassFactory::sLock = {0};
562
563PRTTIMER VirtualBoxClassFactory::sTimer = NULL;
564
565NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR_WITH_RC
566 (VirtualBox, VirtualBoxClassFactory::GetInstance)
567
568////////////////////////////////////////////////////////////////////////////////
569
570typedef NSFactoryDestructorProcPtr NSFactoryConsructorProcPtr;
571
572/**
573 * Enhanced module component information structure.
574 *
575 * nsModuleComponentInfo lacks the factory construction callback, here we add
576 * it. This callback is called by NS_NewGenericFactoryEx() after a
577 * nsGenericFactory instance is successfully created.
578 */
579struct nsModuleComponentInfoEx : nsModuleComponentInfo
580{
581 nsModuleComponentInfoEx () {}
582 nsModuleComponentInfoEx (int) {}
583
584 nsModuleComponentInfoEx (
585 const char* aDescription,
586 const nsCID& aCID,
587 const char* aContractID,
588 NSConstructorProcPtr aConstructor,
589 NSRegisterSelfProcPtr aRegisterSelfProc,
590 NSUnregisterSelfProcPtr aUnregisterSelfProc,
591 NSFactoryDestructorProcPtr aFactoryDestructor,
592 NSGetInterfacesProcPtr aGetInterfacesProc,
593 NSGetLanguageHelperProcPtr aGetLanguageHelperProc,
594 nsIClassInfo ** aClassInfoGlobal,
595 PRUint32 aFlags,
596 NSFactoryConsructorProcPtr aFactoryConstructor)
597 {
598 mDescription = aDescription;
599 mCID = aCID;
600 mContractID = aContractID;
601 mConstructor = aConstructor;
602 mRegisterSelfProc = aRegisterSelfProc;
603 mUnregisterSelfProc = aUnregisterSelfProc;
604 mFactoryDestructor = aFactoryDestructor;
605 mGetInterfacesProc = aGetInterfacesProc;
606 mGetLanguageHelperProc = aGetLanguageHelperProc;
607 mClassInfoGlobal = aClassInfoGlobal;
608 mFlags = aFlags;
609 mFactoryConstructor = aFactoryConstructor;
610 }
611
612 /** (optional) Factory Construction Callback */
613 NSFactoryConsructorProcPtr mFactoryConstructor;
614};
615
616////////////////////////////////////////////////////////////////////////////////
617
618static const nsModuleComponentInfoEx components[] =
619{
620 nsModuleComponentInfoEx (
621 "VirtualBox component",
622 (nsCID) NS_VIRTUALBOX_CID,
623 NS_VIRTUALBOX_CONTRACTID,
624 VirtualBoxConstructor, // constructor funcion
625 NULL, // registration function
626 NULL, // deregistration function
627 VirtualBoxClassFactory::FactoryDestructor, // factory destructor function
628 NS_CI_INTERFACE_GETTER_NAME(VirtualBox),
629 NULL, // language helper
630 &NS_CLASSINFO_NAME(VirtualBox),
631 0, // flags
632 VirtualBoxClassFactory::FactoryConstructor // factory constructor function
633 )
634};
635
636/////////////////////////////////////////////////////////////////////////////
637
638/**
639 * Extends NS_NewGenericFactory() by immediately calling
640 * nsModuleComponentInfoEx::mFactoryConstructor before returning to the
641 * caller.
642 */
643nsresult
644NS_NewGenericFactoryEx (nsIGenericFactory **result,
645 const nsModuleComponentInfoEx *info)
646{
647 AssertReturn (result, NS_ERROR_INVALID_POINTER);
648
649 nsresult rv = NS_NewGenericFactory (result, info);
650 if (NS_SUCCEEDED (rv) && info && info->mFactoryConstructor)
651 {
652 rv = info->mFactoryConstructor();
653 if (NS_FAILED (rv))
654 NS_RELEASE (*result);
655 }
656
657 return rv;
658}
659
660/////////////////////////////////////////////////////////////////////////////
661
662/**
663 * Hhelper function to register self components upon start-up
664 * of the out-of-proc server.
665 */
666static nsresult
667RegisterSelfComponents (nsIComponentRegistrar *registrar,
668 const nsModuleComponentInfoEx *components,
669 PRUint32 count)
670{
671 nsresult rc = NS_OK;
672 const nsModuleComponentInfoEx *info = components;
673 for (PRUint32 i = 0; i < count && NS_SUCCEEDED (rc); i++, info++)
674 {
675 /* skip components w/o a constructor */
676 if (!info->mConstructor) continue;
677 /* create a new generic factory for a component and register it */
678 nsIGenericFactory *factory;
679 rc = NS_NewGenericFactoryEx (&factory, info);
680 if (NS_SUCCEEDED (rc))
681 {
682 rc = registrar->RegisterFactory (info->mCID,
683 info->mDescription,
684 info->mContractID,
685 factory);
686 factory->Release();
687 }
688 }
689 return rc;
690}
691
692/////////////////////////////////////////////////////////////////////////////
693
694static ipcIService *gIpcServ = nsnull;
695static char *pszPidFile = NULL;
696
697class ForceQuitEvent : public MyEvent
698{
699 void *handler()
700 {
701 LogFlowFunc (("\n"));
702
703 gKeepRunning = PR_FALSE;
704
705 if (pszPidFile)
706 RTFileDelete(pszPidFile);
707
708 return NULL;
709 }
710};
711
712static void signal_handler (int sig)
713{
714 if (gEventQ && gKeepRunning)
715 {
716 /* post a quit event to the queue */
717 ForceQuitEvent *ev = new ForceQuitEvent();
718 ev->postTo (gEventQ);
719 }
720}
721
722#if defined(USE_BACKTRACE)
723/**
724 * the signal handler that prints out a backtrace of the call stack.
725 * the code is taken from http://www.linuxjournal.com/article/6391.
726 */
727static void bt_sighandler (int sig, siginfo_t *info, void *secret)
728{
729
730 void *trace[16];
731 char **messages = (char **)NULL;
732 int i, trace_size = 0;
733 ucontext_t *uc = (ucontext_t *)secret;
734
735 // Do something useful with siginfo_t
736 if (sig == SIGSEGV)
737 Log (("Got signal %d, faulty address is %p, from %p\n",
738 sig, info->si_addr, uc->uc_mcontext.gregs[REG_PC]));
739 else
740 Log (("Got signal %d\n", sig));
741
742 trace_size = backtrace (trace, 16);
743 // overwrite sigaction with caller's address
744 trace[1] = (void *) uc->uc_mcontext.gregs [REG_PC];
745
746 messages = backtrace_symbols (trace, trace_size);
747 // skip first stack frame (points here)
748 Log (("[bt] Execution path:\n"));
749 for (i = 1; i < trace_size; ++i)
750 Log (("[bt] %s\n", messages[i]));
751
752 exit (0);
753}
754#endif
755
756int main (int argc, char **argv)
757{
758 const struct option options[] =
759 {
760 { "automate", no_argument, NULL, 'a' },
761#ifdef RT_OS_DARWIN
762 { "auto-shutdown", no_argument, NULL, 'A' },
763#endif
764 { "daemonize", no_argument, NULL, 'd' },
765 { "pidfile", required_argument, NULL, 'p' },
766#ifdef RT_OS_DARWIN
767 { "pipe", required_argument, NULL, 'P' },
768#endif
769 { NULL, 0, NULL, 0 }
770 };
771 int c;
772
773 bool fDaemonize = false;
774#ifndef RT_OS_OS2
775 static int daemon_pipe_fds[2] = {-1, -1};
776#endif
777
778 for (;;)
779 {
780 c = getopt_long(argc, argv, "", options, NULL);
781 if (c == -1)
782 break;
783 switch (c)
784 {
785 case 'a':
786 {
787 /* --automate mode means we are started by XPCOM on
788 * demand. Daemonize ourselves and activate
789 * auto-shutdown. */
790 gAutoShutdown = true;
791 fDaemonize = true;
792 break;
793 }
794
795#ifdef RT_OS_DARWIN
796 /* Used together with '-P', see below. Internal use only. */
797 case 'A':
798 {
799 gAutoShutdown = true;
800 break;
801 }
802#endif
803
804 case 'd':
805 {
806 fDaemonize = true;
807 break;
808 }
809
810 case 'p':
811 {
812 pszPidFile = optarg;
813 break;
814 }
815
816#ifdef RT_OS_DARWIN
817 /* we need to exec on darwin, this is just an internal
818 * hack for passing the pipe fd along to the final child. */
819 case 'P':
820 {
821 daemon_pipe_fds[1] = atoi(optarg);
822 break;
823 }
824#endif
825
826 default:
827 {
828 /* exit on invalid options */
829 return 1;
830 }
831 }
832 }
833
834 static RTFILE pidFile = NIL_RTFILE;
835
836#ifdef RT_OS_OS2
837
838 /* nothing to do here, the process is supposed to be already
839 * started daemonized when it is necessary */
840 NOREF(fDaemonize);
841
842#else // ifdef RT_OS_OS2
843
844 if (fDaemonize)
845 {
846 /* create a pipe for communication between child and parent */
847 if (pipe(daemon_pipe_fds) < 0)
848 {
849 printf("ERROR: pipe() failed (errno = %d)\n", errno);
850 return 1;
851 }
852
853 pid_t childpid = fork();
854 if (childpid == -1)
855 {
856 printf("ERROR: fork() failed (errno = %d)\n", errno);
857 return 1;
858 }
859
860 if (childpid != 0)
861 {
862 /* we're the parent process */
863 bool fSuccess = false;
864
865 /* close the writing end of the pipe */
866 close(daemon_pipe_fds[1]);
867
868 /* try to read a message from the pipe */
869 char msg[10] = {0}; /* initialize so it's NULL terminated */
870 if (read(daemon_pipe_fds[0], msg, sizeof(msg)) > 0)
871 {
872 if (strcmp(msg, "READY") == 0)
873 fSuccess = true;
874 else
875 printf ("ERROR: Unknown message from child "
876 "process (%s)\n", msg);
877 }
878 else
879 printf ("ERROR: 0 bytes read from child process\n");
880
881 /* close the reading end of the pipe as well and exit */
882 close(daemon_pipe_fds[0]);
883 return fSuccess ? 0 : 1;
884 }
885 /* we're the child process */
886
887 /* Create a new SID for the child process */
888 pid_t sid = setsid();
889 if (sid < 0)
890 {
891 printf("ERROR: setsid() failed (errno = %d)\n", errno);
892 return 1;
893 }
894
895 /* Need to do another for to get rid of the session leader status.
896 * Otherwise any accidentally opened tty will automatically become a
897 * controlling tty for the daemon process. */
898 childpid = fork();
899 if (childpid == -1)
900 {
901 printf("ERROR: second fork() failed (errno = %d)\n", errno);
902 return 1;
903 }
904
905 if (childpid != 0)
906 {
907 /* we're the parent process, just a dummy so terminate now */
908 exit(0);
909 }
910
911 /* Redirect standard i/o streams to /dev/null */
912 if (daemon_pipe_fds[0] > 2)
913 {
914 freopen ("/dev/null", "r", stdin);
915 freopen ("/dev/null", "w", stdout);
916 freopen ("/dev/null", "w", stderr);
917 }
918
919 /* close the reading end of the pipe */
920 close(daemon_pipe_fds[0]);
921
922# ifdef RT_OS_DARWIN
923 /*
924 * On leopard we're no longer allowed to use some of the core API's
925 * after forking - this will cause us to hit an int3.
926 * So, we'll have to execv VBoxSVC once again and hand it the pipe
927 * and all other relevant options.
928 */
929 const char *apszArgs[7];
930 int i = 0;
931 apszArgs[i++] = argv[0];
932 apszArgs[i++] = "--pipe";
933 char szPipeArg[32];
934 RTStrPrintf (szPipeArg, sizeof (szPipeArg), "%d", daemon_pipe_fds[1]);
935 apszArgs[i++] = szPipeArg;
936 if (pszPidFile)
937 {
938 apszArgs[i++] = "--pidfile";
939 apszArgs[i++] = pszPidFile;
940 }
941 if (gAutoShutdown)
942 apszArgs[i++] = "--auto-shutdown";
943 apszArgs[i++] = NULL; Assert(i <= RT_ELEMENTS(apszArgs));
944 execv (apszArgs[0], (char * const *)apszArgs);
945 exit (0);
946# endif
947 }
948
949#endif // ifdef RT_OS_OS2
950
951#if defined(USE_BACKTRACE)
952 {
953 /* install our signal handler to backtrace the call stack */
954 struct sigaction sa;
955 sa.sa_sigaction = bt_sighandler;
956 sigemptyset (&sa.sa_mask);
957 sa.sa_flags = SA_RESTART | SA_SIGINFO;
958 sigaction (SIGSEGV, &sa, NULL);
959 sigaction (SIGBUS, &sa, NULL);
960 sigaction (SIGUSR1, &sa, NULL);
961 }
962#endif
963
964 /*
965 * Initialize the VBox runtime without loading
966 * the support driver
967 */
968 RTR3Init(false);
969
970 nsresult rc;
971
972 do
973 {
974 rc = com::Initialize();
975 if (NS_FAILED (rc))
976 {
977 printf ("ERROR: Failed to initialize XPCOM! (rc=%08X)\n", rc);
978 break;
979 }
980
981 nsCOMPtr <nsIComponentRegistrar> registrar;
982 rc = NS_GetComponentRegistrar (getter_AddRefs (registrar));
983 if (NS_FAILED (rc))
984 {
985 printf ("ERROR: Failed to get component registrar! (rc=%08X)\n", rc);
986 break;
987 }
988
989 registrar->AutoRegister (nsnull);
990 rc = RegisterSelfComponents (registrar, components,
991 NS_ARRAY_LENGTH (components));
992 if (NS_FAILED (rc))
993 {
994 printf ("ERROR: Failed to register server components! (rc=%08X)\n", rc);
995 break;
996 }
997
998 /* get the main thread's event queue (afaik, the dconnect service always
999 * gets created upon XPCOM startup, so it will use the main (this)
1000 * thread's event queue to receive IPC events) */
1001 rc = NS_GetMainEventQ (&gEventQ);
1002 if (NS_FAILED (rc))
1003 {
1004 printf ("ERROR: Failed to get the main event queue! (rc=%08X)\n", rc);
1005 break;
1006 }
1007
1008 nsCOMPtr<ipcIService> ipcServ (do_GetService(IPC_SERVICE_CONTRACTID, &rc));
1009 if (NS_FAILED (rc))
1010 {
1011 printf ("ERROR: Failed to get IPC service! (rc=%08X)\n", rc);
1012 break;
1013 }
1014
1015 NS_ADDREF (gIpcServ = ipcServ);
1016
1017 LogFlowFunc (("Will use \"%s\" as server name.\n", VBOXSVC_IPC_NAME));
1018
1019 rc = gIpcServ->AddName (VBOXSVC_IPC_NAME);
1020 if (NS_FAILED (rc))
1021 {
1022 printf ("ERROR: Failed to register VirtualBoxServer! (rc=%08X)\n", rc);
1023 NS_RELEASE (gIpcServ);
1024 break;
1025 }
1026
1027 {
1028 /* setup signal handling to convert some signals to a quit event */
1029 struct sigaction sa;
1030 sa.sa_handler = signal_handler;
1031 sigemptyset (&sa.sa_mask);
1032 sa.sa_flags = 0;
1033 sigaction (SIGINT, &sa, NULL);
1034 sigaction (SIGQUIT, &sa, NULL);
1035 sigaction (SIGTERM, &sa, NULL);
1036 sigaction (SIGTRAP, &sa, NULL);
1037 }
1038
1039 {
1040 char szBuf[80];
1041 int iSize;
1042
1043 iSize = snprintf (szBuf, sizeof(szBuf),
1044 "innotek VirtualBox XPCOM Server Version "
1045 VBOX_VERSION_STRING);
1046 for (int i=iSize; i>0; i--)
1047 putchar('*');
1048 printf ("\n%s\n", szBuf);
1049 printf ("(C) 2004-2008 innotek GmbH\n"
1050 "All rights reserved.\n");
1051#ifdef DEBUG
1052 printf ("Debug version.\n");
1053#endif
1054#if 0
1055 /* in my opinion two lines enclosing the text look better */
1056 for (int i=iSize; i>0; i--)
1057 putchar('*');
1058 putchar('\n');
1059#endif
1060 }
1061
1062#ifndef RT_OS_OS2
1063 if (daemon_pipe_fds[1] >= 0)
1064 {
1065 printf ("\nStarting event loop....\n[send TERM signal to quit]\n");
1066 /* now we're ready, signal the parent process */
1067 write(daemon_pipe_fds[1], "READY", strlen("READY"));
1068 }
1069 else
1070#endif
1071 {
1072 printf ("\nStarting event loop....\n[press Ctrl-C to quit]\n");
1073 }
1074
1075 if (pszPidFile)
1076 {
1077 char szBuf[32];
1078 const char *lf = "\n";
1079 RTFileOpen(&pidFile, pszPidFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE);
1080 RTStrFormatNumber(szBuf, getpid(), 10, 0, 0, 0);
1081 RTFileWrite(pidFile, szBuf, strlen(szBuf), NULL);
1082 RTFileWrite(pidFile, lf, strlen(lf), NULL);
1083 RTFileClose(pidFile);
1084 }
1085
1086 PLEvent *ev;
1087 while (gKeepRunning)
1088 {
1089 gEventQ->WaitForEvent (&ev);
1090 gEventQ->HandleEvent (ev);
1091 }
1092
1093 gIpcServ->RemoveName (VBOXSVC_IPC_NAME);
1094
1095 /* stop accepting new events */
1096 gEventQ->StopAcceptingEvents();
1097
1098 /* process any remaining events */
1099 gEventQ->ProcessPendingEvents();
1100
1101 printf ("Terminated event loop.\n");
1102 }
1103 while (0); // this scopes the nsCOMPtrs
1104
1105 NS_IF_RELEASE (gIpcServ);
1106 NS_IF_RELEASE (gEventQ);
1107
1108 /* no nsCOMPtrs are allowed to be alive when you call com::Shutdown(). */
1109
1110 LogFlowFunc (("Calling com::Shutdown()...\n"));
1111 rc = com::Shutdown();
1112 LogFlowFunc (("Finished com::Shutdown() (rc=%08X)\n", rc));
1113
1114 if (NS_FAILED (rc))
1115 printf ("ERROR: Failed to shutdown XPCOM! (rc=%08X)\n", rc);
1116
1117 printf ("XPCOM server has shutdown.\n");
1118
1119 if (pszPidFile)
1120 {
1121 RTFileDelete(pszPidFile);
1122 }
1123
1124#ifndef RT_OS_OS2
1125 if (daemon_pipe_fds[1] >= 0)
1126 {
1127 /* close writing end of the pipe as well */
1128 close(daemon_pipe_fds[1]);
1129 }
1130#endif
1131
1132 return 0;
1133}
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