VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/HostImpl.cpp@ 41100

Last change on this file since 41100 was 41025, checked in by vboxsync, 13 years ago

Main/Host: fix a few LogRel messages

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 102.7 KB
Line 
1/* $Id: HostImpl.cpp 41025 2012-04-23 12:59:52Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Host
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
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#define __STDC_LIMIT_MACROS
19#define __STDC_CONSTANT_MACROS
20
21// for some reason Windows burns in sdk\...\winsock.h if this isn't included first
22#include "VBox/com/ptr.h"
23
24#include "HostImpl.h"
25
26#ifdef VBOX_WITH_USB
27# include "HostUSBDeviceImpl.h"
28# include "USBDeviceFilterImpl.h"
29# include "USBProxyService.h"
30#endif // VBOX_WITH_USB
31
32#include "HostNetworkInterfaceImpl.h"
33#include "MachineImpl.h"
34#include "AutoCaller.h"
35#include "Logging.h"
36#include "Performance.h"
37
38#include "MediumImpl.h"
39#include "HostPower.h"
40
41#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
42# include <HostHardwareLinux.h>
43#endif
44
45#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
46# include <set>
47#endif
48
49#ifdef VBOX_WITH_RESOURCE_USAGE_API
50# include "PerformanceImpl.h"
51#endif /* VBOX_WITH_RESOURCE_USAGE_API */
52
53#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
54# include <VBox/VBoxNetCfg-win.h>
55#endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
56
57#ifdef RT_OS_LINUX
58# include <sys/ioctl.h>
59# include <errno.h>
60# include <net/if.h>
61# include <net/if_arp.h>
62#endif /* RT_OS_LINUX */
63
64#ifdef RT_OS_SOLARIS
65# include <fcntl.h>
66# include <unistd.h>
67# include <stropts.h>
68# include <errno.h>
69# include <limits.h>
70# include <stdio.h>
71# include <libdevinfo.h>
72# include <sys/mkdev.h>
73# include <sys/scsi/generic/inquiry.h>
74# include <net/if.h>
75# include <sys/socket.h>
76# include <sys/sockio.h>
77# include <net/if_arp.h>
78# include <net/if.h>
79# include <sys/types.h>
80# include <sys/stat.h>
81# include <sys/cdio.h>
82# include <sys/dkio.h>
83# include <sys/mnttab.h>
84# include <sys/mntent.h>
85/* Dynamic loading of libhal on Solaris hosts */
86# ifdef VBOX_USE_LIBHAL
87# include "vbox-libhal.h"
88extern "C" char *getfullrawname(char *);
89# endif
90# include "solaris/DynLoadLibSolaris.h"
91
92/**
93 * Solaris DVD drive list as returned by getDVDInfoFromDevTree().
94 */
95typedef struct SOLARISDVD
96{
97 struct SOLARISDVD *pNext;
98 char szDescription[512];
99 char szRawDiskPath[PATH_MAX];
100} SOLARISDVD;
101/** Pointer to a Solaris DVD descriptor. */
102typedef SOLARISDVD *PSOLARISDVD;
103
104#endif /* RT_OS_SOLARIS */
105
106#ifdef RT_OS_WINDOWS
107# define _WIN32_DCOM
108# include <windows.h>
109# include <shellapi.h>
110# define INITGUID
111# include <guiddef.h>
112# include <devguid.h>
113# include <objbase.h>
114//# include <setupapi.h>
115# include <shlobj.h>
116# include <cfgmgr32.h>
117
118#endif /* RT_OS_WINDOWS */
119
120#ifdef RT_OS_DARWIN
121# include "darwin/iokit.h"
122#endif
123
124#ifdef VBOX_WITH_CROGL
125#include <VBox/VBoxOGLTest.h>
126#endif /* VBOX_WITH_CROGL */
127
128#include <iprt/asm-amd64-x86.h>
129#include <iprt/string.h>
130#include <iprt/mp.h>
131#include <iprt/time.h>
132#include <iprt/param.h>
133#include <iprt/env.h>
134#include <iprt/mem.h>
135#include <iprt/system.h>
136#ifdef RT_OS_SOLARIS
137# include <iprt/path.h>
138# include <iprt/ctype.h>
139#endif
140#ifdef VBOX_WITH_HOSTNETIF_API
141# include "netif.h"
142#endif
143
144/* XXX Solaris: definitions in /usr/include/sys/regset.h clash with hwacc_svm.h */
145#undef DS
146#undef ES
147#undef CS
148#undef SS
149#undef FS
150#undef GS
151
152#include <VBox/usb.h>
153#include <VBox/vmm/hwacc_svm.h>
154#include <VBox/err.h>
155#include <VBox/settings.h>
156#include <VBox/sup.h>
157#include <iprt/x86.h>
158
159#include "VBox/com/MultiResult.h"
160
161#include <stdio.h>
162
163#include <algorithm>
164
165////////////////////////////////////////////////////////////////////////////////
166//
167// Host private data definition
168//
169////////////////////////////////////////////////////////////////////////////////
170
171struct Host::Data
172{
173 Data()
174 :
175#ifdef VBOX_WITH_USB
176 usbListsLock(LOCKCLASS_USBLIST),
177#endif
178 fDVDDrivesListBuilt(false),
179 fFloppyDrivesListBuilt(false)
180 {};
181
182 VirtualBox *pParent;
183
184#ifdef VBOX_WITH_USB
185 WriteLockHandle usbListsLock; // protects the below two lists
186
187 USBDeviceFilterList llChildren; // all USB device filters
188 USBDeviceFilterList llUSBDeviceFilters; // USB device filters in use by the USB proxy service
189
190 /** Pointer to the USBProxyService object. */
191 USBProxyService *pUSBProxyService;
192#endif /* VBOX_WITH_USB */
193
194 // list of host drives; lazily created by getDVDDrives() and getFloppyDrives(),
195 // and protected by the medium tree lock handle (including the bools).
196 MediaList llDVDDrives,
197 llFloppyDrives;
198 bool fDVDDrivesListBuilt,
199 fFloppyDrivesListBuilt;
200
201#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
202 /** Object with information about host drives */
203 VBoxMainDriveInfo hostDrives;
204#endif
205 /* Features that can be queried with GetProcessorFeature */
206 BOOL fVTSupported,
207 fLongModeSupported,
208 fPAESupported,
209 fNestedPagingSupported;
210
211 /* 3D hardware acceleration supported? */
212 BOOL f3DAccelerationSupported;
213
214 HostPowerService *pHostPowerService;
215};
216
217
218////////////////////////////////////////////////////////////////////////////////
219//
220// Constructor / destructor
221//
222////////////////////////////////////////////////////////////////////////////////
223
224HRESULT Host::FinalConstruct()
225{
226 return BaseFinalConstruct();
227}
228
229void Host::FinalRelease()
230{
231 uninit();
232 BaseFinalRelease();
233}
234
235/**
236 * Initializes the host object.
237 *
238 * @param aParent VirtualBox parent object.
239 */
240HRESULT Host::init(VirtualBox *aParent)
241{
242 HRESULT hrc;
243 LogFlowThisFunc(("aParent=%p\n", aParent));
244
245 /* Enclose the state transition NotReady->InInit->Ready */
246 AutoInitSpan autoInitSpan(this);
247 AssertReturn(autoInitSpan.isOk(), E_FAIL);
248
249 m = new Data();
250
251 m->pParent = aParent;
252
253#ifdef VBOX_WITH_USB
254 /*
255 * Create and initialize the USB Proxy Service.
256 */
257# if defined (RT_OS_DARWIN)
258 m->pUSBProxyService = new USBProxyServiceDarwin(this);
259# elif defined (RT_OS_LINUX)
260 m->pUSBProxyService = new USBProxyServiceLinux(this);
261# elif defined (RT_OS_OS2)
262 m->pUSBProxyService = new USBProxyServiceOs2(this);
263# elif defined (RT_OS_SOLARIS)
264 m->pUSBProxyService = new USBProxyServiceSolaris(this);
265# elif defined (RT_OS_WINDOWS)
266 m->pUSBProxyService = new USBProxyServiceWindows(this);
267# elif defined (RT_OS_FREEBSD)
268 m->pUSBProxyService = new USBProxyServiceFreeBSD(this);
269# else
270 m->pUSBProxyService = new USBProxyService(this);
271# endif
272 hrc = m->pUSBProxyService->init();
273 AssertComRCReturn(hrc, hrc);
274#endif /* VBOX_WITH_USB */
275
276#ifdef VBOX_WITH_RESOURCE_USAGE_API
277 registerMetrics(aParent->performanceCollector());
278#endif /* VBOX_WITH_RESOURCE_USAGE_API */
279
280#if defined (RT_OS_WINDOWS)
281 m->pHostPowerService = new HostPowerServiceWin(m->pParent);
282#elif defined (RT_OS_DARWIN)
283 m->pHostPowerService = new HostPowerServiceDarwin(m->pParent);
284#else
285 m->pHostPowerService = new HostPowerService(m->pParent);
286#endif
287
288 /* Cache the features reported by GetProcessorFeature. */
289 m->fVTSupported = false;
290 m->fLongModeSupported = false;
291 m->fPAESupported = false;
292 m->fNestedPagingSupported = false;
293
294 if (ASMHasCpuId())
295 {
296 uint32_t u32FeaturesECX;
297 uint32_t u32Dummy;
298 uint32_t u32FeaturesEDX;
299 uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32AMDFeatureEDX, u32AMDFeatureECX;
300
301 ASMCpuId(0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX);
302 ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX);
303 /* Query AMD features. */
304 ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &u32AMDFeatureECX, &u32AMDFeatureEDX);
305
306 m->fLongModeSupported = !!(u32AMDFeatureEDX & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE);
307 m->fPAESupported = !!(u32FeaturesEDX & X86_CPUID_FEATURE_EDX_PAE);
308
309 if ( u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX
310 && u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX
311 && u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX
312 )
313 {
314 if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
315 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
316 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
317 )
318 {
319 int rc = SUPR3QueryVTxSupported();
320 if (RT_SUCCESS(rc))
321 m->fVTSupported = true;
322 }
323 }
324 else
325 if ( u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX
326 && u32VendorECX == X86_CPUID_VENDOR_AMD_ECX
327 && u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX
328 )
329 {
330 if ( (u32AMDFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM)
331 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
332 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
333 )
334 {
335 uint32_t u32SVMFeatureEDX;
336
337 m->fVTSupported = true;
338
339 /* Query AMD features. */
340 ASMCpuId(0x8000000A, &u32Dummy, &u32Dummy, &u32Dummy, &u32SVMFeatureEDX);
341 if (u32SVMFeatureEDX & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING)
342 m->fNestedPagingSupported = true;
343 }
344 }
345 }
346
347#if 0 /* needs testing */
348 if (m->fVTSupported)
349 {
350 uint32_t u32Caps = 0;
351
352 int rc = SUPR3QueryVTCaps(&u32Caps);
353 if (RT_SUCCESS(rc))
354 {
355 if (u32Caps & SUPVTCAPS_NESTED_PAGING)
356 m->fNestedPagingSupported = true;
357 }
358 /* else @todo; report BIOS trouble in some way. */
359 }
360#endif
361
362 /* Test for 3D hardware acceleration support */
363 m->f3DAccelerationSupported = false;
364
365#ifdef VBOX_WITH_CROGL
366 m->f3DAccelerationSupported = VBoxOglIs3DAccelerationSupported();
367#endif /* VBOX_WITH_CROGL */
368
369#if defined (RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
370 /* Extract the list of configured host-only interfaces */
371 std::set<Utf8Str> aConfiguredNames;
372 SafeArray<BSTR> aGlobalExtraDataKeys;
373 hrc = aParent->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
374 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
375 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
376 {
377 Utf8Str strKey = aGlobalExtraDataKeys[i];
378
379 if (!strKey.startsWith("HostOnly/vboxnet"))
380 continue;
381
382 size_t pos = strKey.find("/", sizeof("HostOnly/vboxnet"));
383 if (pos != Utf8Str::npos)
384 aConfiguredNames.insert(strKey.substr(sizeof("HostOnly"),
385 pos - sizeof("HostOnly")));
386 }
387
388 for (std::set<Utf8Str>::const_iterator it = aConfiguredNames.begin();
389 it != aConfiguredNames.end();
390 ++it)
391 {
392 ComPtr<IHostNetworkInterface> hif;
393 ComPtr<IProgress> progress;
394
395 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent,
396 hif.asOutParam(),
397 progress.asOutParam(),
398 it->c_str());
399 if (RT_FAILURE(r))
400 LogRel(("failed to create %s, error (0x%x)\n", it->c_str(), r));
401 }
402
403#endif /* defined (RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) */
404
405 /* Confirm a successful initialization */
406 autoInitSpan.setSucceeded();
407
408 return S_OK;
409}
410
411/**
412 * Uninitializes the host object and sets the ready flag to FALSE.
413 * Called either from FinalRelease() or by the parent when it gets destroyed.
414 */
415void Host::uninit()
416{
417 LogFlowThisFunc(("\n"));
418
419 /* Enclose the state transition Ready->InUninit->NotReady */
420 AutoUninitSpan autoUninitSpan(this);
421 if (autoUninitSpan.uninitDone())
422 return;
423
424#ifdef VBOX_WITH_RESOURCE_USAGE_API
425 unregisterMetrics (m->pParent->performanceCollector());
426#endif /* VBOX_WITH_RESOURCE_USAGE_API */
427
428#ifdef VBOX_WITH_USB
429 /* wait for USB proxy service to terminate before we uninit all USB
430 * devices */
431 LogFlowThisFunc(("Stopping USB proxy service...\n"));
432 delete m->pUSBProxyService;
433 m->pUSBProxyService = NULL;
434 LogFlowThisFunc(("Done stopping USB proxy service.\n"));
435#endif
436
437 delete m->pHostPowerService;
438
439#ifdef VBOX_WITH_USB
440 /* uninit all USB device filters still referenced by clients
441 * Note! HostUSBDeviceFilter::uninit() will modify llChildren. */
442 while (!m->llChildren.empty())
443 {
444 ComObjPtr<HostUSBDeviceFilter> &pChild = m->llChildren.front();
445 pChild->uninit();
446 }
447
448 m->llUSBDeviceFilters.clear();
449#endif
450
451 delete m;
452 m = NULL;
453}
454
455////////////////////////////////////////////////////////////////////////////////
456//
457// ISnapshot public methods
458//
459////////////////////////////////////////////////////////////////////////////////
460
461/**
462 * Returns a list of host DVD drives.
463 *
464 * @returns COM status code
465 * @param drives address of result pointer
466 */
467STDMETHODIMP Host::COMGETTER(DVDDrives)(ComSafeArrayOut(IMedium *, aDrives))
468{
469 CheckComArgOutSafeArrayPointerValid(aDrives);
470
471 AutoCaller autoCaller(this);
472 if (FAILED(autoCaller.rc())) return autoCaller.rc();
473
474 AutoWriteLock alock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
475
476 MediaList *pList;
477 HRESULT rc = getDrives(DeviceType_DVD, true /* fRefresh */, pList);
478 if (SUCCEEDED(rc))
479 {
480 SafeIfaceArray<IMedium> array(*pList);
481 array.detachTo(ComSafeArrayOutArg(aDrives));
482 }
483
484 return rc;
485}
486
487/**
488 * Returns a list of host floppy drives.
489 *
490 * @returns COM status code
491 * @param drives address of result pointer
492 */
493STDMETHODIMP Host::COMGETTER(FloppyDrives)(ComSafeArrayOut(IMedium *, aDrives))
494{
495 CheckComArgOutPointerValid(aDrives);
496
497 AutoCaller autoCaller(this);
498 if (FAILED(autoCaller.rc())) return autoCaller.rc();
499
500 AutoWriteLock alock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
501
502 MediaList *pList;
503 HRESULT rc = getDrives(DeviceType_Floppy, true /* fRefresh */, pList);
504 if (SUCCEEDED(rc))
505 {
506 SafeIfaceArray<IMedium> collection(*pList);
507 collection.detachTo(ComSafeArrayOutArg(aDrives));
508 }
509
510 return rc;
511}
512
513
514#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
515# define VBOX_APP_NAME L"VirtualBox"
516
517static int vboxNetWinAddComponent(std::list< ComObjPtr<HostNetworkInterface> > *pPist,
518 INetCfgComponent *pncc)
519{
520 LPWSTR lpszName;
521 GUID IfGuid;
522 HRESULT hr;
523 int rc = VERR_GENERAL_FAILURE;
524
525 hr = pncc->GetDisplayName( &lpszName );
526 Assert(hr == S_OK);
527 if (hr == S_OK)
528 {
529 Bstr name((CBSTR)lpszName);
530
531 hr = pncc->GetInstanceGuid(&IfGuid);
532 Assert(hr == S_OK);
533 if (hr == S_OK)
534 {
535 /* create a new object and add it to the list */
536 ComObjPtr<HostNetworkInterface> iface;
537 iface.createObject();
538 /* remove the curly bracket at the end */
539 if (SUCCEEDED(iface->init (name, name, Guid (IfGuid), HostNetworkInterfaceType_Bridged)))
540 {
541// iface->setVirtualBox(m->pParent);
542 pPist->push_back(iface);
543 rc = VINF_SUCCESS;
544 }
545 else
546 {
547 Assert(0);
548 }
549 }
550 CoTaskMemFree(lpszName);
551 }
552
553 return rc;
554}
555#endif /* defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
556
557/**
558 * Returns a list of host network interfaces.
559 *
560 * @returns COM status code
561 * @param drives address of result pointer
562 */
563STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInterface*, aNetworkInterfaces))
564{
565#if defined(RT_OS_WINDOWS) || defined(VBOX_WITH_NETFLT) /*|| defined(RT_OS_OS2)*/
566 if (ComSafeArrayOutIsNull(aNetworkInterfaces))
567 return E_POINTER;
568
569 AutoCaller autoCaller(this);
570 if (FAILED(autoCaller.rc())) return autoCaller.rc();
571
572 std::list<ComObjPtr<HostNetworkInterface> > list;
573
574# ifdef VBOX_WITH_HOSTNETIF_API
575 int rc = NetIfList(list);
576 if (rc)
577 {
578 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
579 }
580# else
581
582# if defined(RT_OS_DARWIN)
583 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
584 while (pEtherNICs)
585 {
586 ComObjPtr<HostNetworkInterface> IfObj;
587 IfObj.createObject();
588 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid), HostNetworkInterfaceType_Bridged)))
589 list.push_back(IfObj);
590
591 /* next, free current */
592 void *pvFree = pEtherNICs;
593 pEtherNICs = pEtherNICs->pNext;
594 RTMemFree(pvFree);
595 }
596
597# elif defined RT_OS_WINDOWS
598# ifndef VBOX_WITH_NETFLT
599 hr = E_NOTIMPL;
600# else /* # if defined VBOX_WITH_NETFLT */
601 INetCfg *pNc;
602 INetCfgComponent *pMpNcc;
603 INetCfgComponent *pTcpIpNcc;
604 LPWSTR lpszApp;
605 HRESULT hr;
606 IEnumNetCfgBindingPath *pEnumBp;
607 INetCfgBindingPath *pBp;
608 IEnumNetCfgBindingInterface *pEnumBi;
609 INetCfgBindingInterface *pBi;
610
611 /* we are using the INetCfg API for getting the list of miniports */
612 hr = VBoxNetCfgWinQueryINetCfg( FALSE,
613 VBOX_APP_NAME,
614 &pNc,
615 &lpszApp );
616 Assert(hr == S_OK);
617 if (hr == S_OK)
618 {
619# ifdef VBOX_NETFLT_ONDEMAND_BIND
620 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
621 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
622# else
623 /* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
624 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
625# ifndef VBOX_WITH_HARDENING
626 if (hr != S_OK)
627 {
628 /* TODO: try to install the netflt from here */
629 }
630# endif
631
632# endif
633
634 if (hr == S_OK)
635 {
636 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
637 Assert(hr == S_OK);
638 if ( hr == S_OK )
639 {
640 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
641 Assert(hr == S_OK || hr == S_FALSE);
642 while( hr == S_OK )
643 {
644 /* S_OK == enabled, S_FALSE == disabled */
645 if (pBp->IsEnabled() == S_OK)
646 {
647 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
648 Assert(hr == S_OK);
649 if ( hr == S_OK )
650 {
651 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
652 Assert(hr == S_OK);
653 while(hr == S_OK)
654 {
655 hr = pBi->GetLowerComponent( &pMpNcc );
656 Assert(hr == S_OK);
657 if (hr == S_OK)
658 {
659 ULONG uComponentStatus;
660 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
661 Assert(hr == S_OK);
662 if (hr == S_OK)
663 {
664 if (uComponentStatus == 0)
665 {
666 vboxNetWinAddComponent(&list, pMpNcc);
667 }
668 }
669 VBoxNetCfgWinReleaseRef( pMpNcc );
670 }
671 VBoxNetCfgWinReleaseRef(pBi);
672
673 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
674 }
675 VBoxNetCfgWinReleaseRef(pEnumBi);
676 }
677 }
678 VBoxNetCfgWinReleaseRef(pBp);
679
680 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
681 }
682 VBoxNetCfgWinReleaseRef(pEnumBp);
683 }
684 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
685 }
686 else
687 {
688 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)\n", hr));
689 }
690
691 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
692 }
693# endif /* # if defined VBOX_WITH_NETFLT */
694
695
696# elif defined RT_OS_LINUX
697 int sock = socket(AF_INET, SOCK_DGRAM, 0);
698 if (sock >= 0)
699 {
700 char pBuffer[2048];
701 struct ifconf ifConf;
702 ifConf.ifc_len = sizeof(pBuffer);
703 ifConf.ifc_buf = pBuffer;
704 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
705 {
706 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
707 {
708 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
709 {
710 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
711 {
712 RTUUID uuid;
713 Assert(sizeof(uuid) <= sizeof(*pReq));
714 memcpy(&uuid, pReq, sizeof(uuid));
715
716 ComObjPtr<HostNetworkInterface> IfObj;
717 IfObj.createObject();
718 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid), HostNetworkInterfaceType_Bridged)))
719 list.push_back(IfObj);
720 }
721 }
722 }
723 }
724 close(sock);
725 }
726# endif /* RT_OS_LINUX */
727# endif
728
729 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
730 for (it = list.begin(); it != list.end(); ++it)
731 {
732 (*it)->setVirtualBox(m->pParent);
733 }
734
735 SafeIfaceArray<IHostNetworkInterface> networkInterfaces (list);
736 networkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
737
738 return S_OK;
739
740#else
741 /* Not implemented / supported on this platform. */
742 ReturnComNotImplemented();
743#endif
744}
745
746STDMETHODIMP Host::COMGETTER(USBDevices)(ComSafeArrayOut(IHostUSBDevice*, aUSBDevices))
747{
748#ifdef VBOX_WITH_USB
749 CheckComArgOutSafeArrayPointerValid(aUSBDevices);
750
751 AutoCaller autoCaller(this);
752 if (FAILED(autoCaller.rc())) return autoCaller.rc();
753
754 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
755
756 HRESULT rc = checkUSBProxyService();
757 if (FAILED(rc)) return rc;
758
759 return m->pUSBProxyService->getDeviceCollection(ComSafeArrayOutArg(aUSBDevices));
760
761#else
762 /* Note: The GUI depends on this method returning E_NOTIMPL with no
763 * extended error info to indicate that USB is simply not available
764 * (w/o treating it as a failure), for example, as in OSE. */
765 NOREF(aUSBDevices);
766# ifndef RT_OS_WINDOWS
767 NOREF(aUSBDevicesSize);
768# endif
769 ReturnComNotImplemented();
770#endif
771}
772
773STDMETHODIMP Host::COMGETTER(USBDeviceFilters)(ComSafeArrayOut(IHostUSBDeviceFilter*, aUSBDeviceFilters))
774{
775#ifdef VBOX_WITH_USB
776 CheckComArgOutSafeArrayPointerValid(aUSBDeviceFilters);
777
778 AutoCaller autoCaller(this);
779 if (FAILED(autoCaller.rc())) return autoCaller.rc();
780
781 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
782
783 HRESULT rc = checkUSBProxyService();
784 if (FAILED(rc)) return rc;
785
786 SafeIfaceArray<IHostUSBDeviceFilter> collection(m->llUSBDeviceFilters);
787 collection.detachTo(ComSafeArrayOutArg(aUSBDeviceFilters));
788
789 return rc;
790#else
791 /* Note: The GUI depends on this method returning E_NOTIMPL with no
792 * extended error info to indicate that USB is simply not available
793 * (w/o treating it as a failure), for example, as in OSE. */
794 NOREF(aUSBDeviceFilters);
795# ifndef RT_OS_WINDOWS
796 NOREF(aUSBDeviceFiltersSize);
797# endif
798 ReturnComNotImplemented();
799#endif
800}
801
802/**
803 * Returns the number of installed logical processors
804 *
805 * @returns COM status code
806 * @param count address of result variable
807 */
808STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *aCount)
809{
810 CheckComArgOutPointerValid(aCount);
811 // no locking required
812
813 *aCount = RTMpGetPresentCount();
814 return S_OK;
815}
816
817/**
818 * Returns the number of online logical processors
819 *
820 * @returns COM status code
821 * @param count address of result variable
822 */
823STDMETHODIMP Host::COMGETTER(ProcessorOnlineCount)(ULONG *aCount)
824{
825 CheckComArgOutPointerValid(aCount);
826 // no locking required
827
828 *aCount = RTMpGetOnlineCount();
829 return S_OK;
830}
831
832/**
833 * Returns the number of installed physical processor cores.
834 *
835 * @returns COM status code
836 * @param count address of result variable
837 */
838STDMETHODIMP Host::COMGETTER(ProcessorCoreCount)(ULONG *aCount)
839{
840 CheckComArgOutPointerValid(aCount);
841 // no locking required
842
843 return E_NOTIMPL;
844}
845
846/**
847 * Returns the (approximate) maximum speed of the given host CPU in MHz
848 *
849 * @returns COM status code
850 * @param cpu id to get info for.
851 * @param speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
852 */
853STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *aSpeed)
854{
855 CheckComArgOutPointerValid(aSpeed);
856 // no locking required
857
858 *aSpeed = RTMpGetMaxFrequency(aCpuId);
859 return S_OK;
860}
861
862/**
863 * Returns a description string for the host CPU
864 *
865 * @returns COM status code
866 * @param cpu id to get info for.
867 * @param description address of result variable, empty string if not known or aCpuId is invalid.
868 */
869STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription)
870{
871 CheckComArgOutPointerValid(aDescription);
872 // no locking required
873
874 char szCPUModel[80];
875 int vrc = RTMpGetDescription(aCpuId, szCPUModel, sizeof(szCPUModel));
876 if (RT_FAILURE(vrc))
877 return E_FAIL; /** @todo error reporting? */
878 Bstr (szCPUModel).cloneTo(aDescription);
879 return S_OK;
880}
881
882/**
883 * Returns whether a host processor feature is supported or not
884 *
885 * @returns COM status code
886 * @param Feature to query.
887 * @param address of supported bool result variable
888 */
889STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
890{
891 CheckComArgOutPointerValid(aSupported);
892 AutoCaller autoCaller(this);
893 if (FAILED(autoCaller.rc())) return autoCaller.rc();
894
895 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
896
897 switch (aFeature)
898 {
899 case ProcessorFeature_HWVirtEx:
900 *aSupported = m->fVTSupported;
901 break;
902
903 case ProcessorFeature_PAE:
904 *aSupported = m->fPAESupported;
905 break;
906
907 case ProcessorFeature_LongMode:
908 *aSupported = m->fLongModeSupported;
909 break;
910
911 case ProcessorFeature_NestedPaging:
912 *aSupported = m->fNestedPagingSupported;
913 break;
914
915 default:
916 ReturnComNotImplemented();
917 }
918 return S_OK;
919}
920
921/**
922 * Returns the specific CPUID leaf.
923 *
924 * @returns COM status code
925 * @param aCpuId The CPU number. Mostly ignored.
926 * @param aLeaf The leaf number.
927 * @param aSubLeaf The sub-leaf number.
928 * @param aValEAX Where to return EAX.
929 * @param aValEBX Where to return EBX.
930 * @param aValECX Where to return ECX.
931 * @param aValEDX Where to return EDX.
932 */
933STDMETHODIMP Host::GetProcessorCPUIDLeaf(ULONG aCpuId, ULONG aLeaf, ULONG aSubLeaf,
934 ULONG *aValEAX, ULONG *aValEBX, ULONG *aValECX, ULONG *aValEDX)
935{
936 CheckComArgOutPointerValid(aValEAX);
937 CheckComArgOutPointerValid(aValEBX);
938 CheckComArgOutPointerValid(aValECX);
939 CheckComArgOutPointerValid(aValEDX);
940 // no locking required
941
942 /* Check that the CPU is online. */
943 /** @todo later use RTMpOnSpecific. */
944 if (!RTMpIsCpuOnline(aCpuId))
945 return RTMpIsCpuPresent(aCpuId)
946 ? setError(E_FAIL, tr("CPU no.%u is not present"), aCpuId)
947 : setError(E_FAIL, tr("CPU no.%u is not online"), aCpuId);
948
949 uint32_t uEAX, uEBX, uECX, uEDX;
950 ASMCpuId_Idx_ECX(aLeaf, aSubLeaf, &uEAX, &uEBX, &uECX, &uEDX);
951 *aValEAX = uEAX;
952 *aValEBX = uEBX;
953 *aValECX = uECX;
954 *aValEDX = uEDX;
955
956 return S_OK;
957}
958
959/**
960 * Returns the amount of installed system memory in megabytes
961 *
962 * @returns COM status code
963 * @param size address of result variable
964 */
965STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
966{
967 CheckComArgOutPointerValid(aSize);
968 // no locking required
969
970 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
971 pm::CollectorHAL *hal = pm::createHAL();
972 if (!hal)
973 return E_FAIL;
974 ULONG tmp;
975 int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
976 *aSize /= 1024;
977 delete hal;
978 return rc;
979}
980
981/**
982 * Returns the current system memory free space in megabytes
983 *
984 * @returns COM status code
985 * @param available address of result variable
986 */
987STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
988{
989 CheckComArgOutPointerValid(aAvailable);
990 // no locking required
991
992 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
993 pm::CollectorHAL *hal = pm::createHAL();
994 if (!hal)
995 return E_FAIL;
996 ULONG tmp;
997 int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
998 *aAvailable /= 1024;
999 delete hal;
1000 return rc;
1001}
1002
1003/**
1004 * Returns the name string of the host operating system
1005 *
1006 * @returns COM status code
1007 * @param os address of result variable
1008 */
1009STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
1010{
1011 CheckComArgOutPointerValid(aOs);
1012 // no locking required
1013
1014 char szOSName[80];
1015 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
1016 if (RT_FAILURE(vrc))
1017 return E_FAIL; /** @todo error reporting? */
1018 Bstr (szOSName).cloneTo(aOs);
1019 return S_OK;
1020}
1021
1022/**
1023 * Returns the version string of the host operating system
1024 *
1025 * @returns COM status code
1026 * @param os address of result variable
1027 */
1028STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
1029{
1030 CheckComArgOutPointerValid(aVersion);
1031 // no locking required
1032
1033 /* Get the OS release. Reserve some buffer space for the service pack. */
1034 char szOSRelease[128];
1035 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
1036 if (RT_FAILURE(vrc))
1037 return E_FAIL; /** @todo error reporting? */
1038
1039 /* Append the service pack if present. */
1040 char szOSServicePack[80];
1041 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
1042 if (RT_FAILURE(vrc))
1043 {
1044 if (vrc != VERR_NOT_SUPPORTED)
1045 return E_FAIL; /** @todo error reporting? */
1046 szOSServicePack[0] = '\0';
1047 }
1048 if (szOSServicePack[0] != '\0')
1049 {
1050 char *psz = strchr(szOSRelease, '\0');
1051 RTStrPrintf(psz, &szOSRelease[sizeof(szOSRelease)] - psz, "sp%s", szOSServicePack);
1052 }
1053
1054 Bstr(szOSRelease).cloneTo(aVersion);
1055 return S_OK;
1056}
1057
1058/**
1059 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1060 *
1061 * @returns COM status code
1062 * @param time address of result variable
1063 */
1064STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
1065{
1066 CheckComArgOutPointerValid(aUTCTime);
1067 // no locking required
1068
1069 RTTIMESPEC now;
1070 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1071
1072 return S_OK;
1073}
1074
1075STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported)
1076{
1077 CheckComArgOutPointerValid(aSupported);
1078 AutoCaller autoCaller(this);
1079 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1080
1081 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1082
1083 *aSupported = m->f3DAccelerationSupported;
1084
1085#ifdef DEBUG_misha
1086 AssertMsgFailed(("should not be here any more!\n"));
1087#endif
1088
1089 return S_OK;
1090}
1091
1092STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface,
1093 IProgress **aProgress)
1094{
1095 CheckComArgOutPointerValid(aHostNetworkInterface);
1096 CheckComArgOutPointerValid(aProgress);
1097
1098 AutoCaller autoCaller(this);
1099 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1100
1101#ifdef VBOX_WITH_HOSTNETIF_API
1102 /* No need to lock anything. If there ever will - watch out, the function
1103 * called below grabs the VirtualBox lock. */
1104
1105 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostNetworkInterface, aProgress);
1106 if (RT_SUCCESS(r))
1107 {
1108 if (!*aHostNetworkInterface)
1109 return setError(E_FAIL,
1110 tr("Unable to create a host network interface"));
1111
1112#if !defined(RT_OS_WINDOWS)
1113 Bstr tmpAddr, tmpMask, tmpName;
1114 HRESULT hrc;
1115 hrc = (*aHostNetworkInterface)->COMGETTER(Name)(tmpName.asOutParam());
1116 ComAssertComRCRet(hrc, hrc);
1117 hrc = (*aHostNetworkInterface)->COMGETTER(IPAddress)(tmpAddr.asOutParam());
1118 ComAssertComRCRet(hrc, hrc);
1119 hrc = (*aHostNetworkInterface)->COMGETTER(NetworkMask)(tmpMask.asOutParam());
1120 ComAssertComRCRet(hrc, hrc);
1121 /*
1122 * We need to write the default IP address and mask to extra data now,
1123 * so the interface gets re-created after vboxnetadp.ko reload.
1124 * Note that we avoid calling EnableStaticIpConfig since it would
1125 * change the address on host's interface as well and we want to
1126 * postpone the change until VM actually starts.
1127 */
1128 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress",
1129 tmpName.raw()).raw(),
1130 tmpAddr.raw());
1131 ComAssertComRCRet(hrc, hrc);
1132
1133 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask",
1134 tmpName.raw()).raw(),
1135 tmpMask.raw());
1136 ComAssertComRCRet(hrc, hrc);
1137#endif
1138 return S_OK;
1139 }
1140
1141 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1142#else
1143 return E_NOTIMPL;
1144#endif
1145}
1146
1147STDMETHODIMP Host::RemoveHostOnlyNetworkInterface(IN_BSTR aId,
1148 IProgress **aProgress)
1149{
1150 CheckComArgOutPointerValid(aProgress);
1151
1152 AutoCaller autoCaller(this);
1153 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1154
1155#ifdef VBOX_WITH_HOSTNETIF_API
1156 /* No need to lock anything, the code below does not touch the state
1157 * of the host object. If that ever changes then check for lock order
1158 * violations with the called functions. */
1159
1160 Bstr name;
1161 HRESULT rc;
1162
1163 /* first check whether an interface with the given name already exists */
1164 {
1165 ComPtr<IHostNetworkInterface> iface;
1166 if (FAILED(FindHostNetworkInterfaceById(aId,
1167 iface.asOutParam())))
1168 return setError(VBOX_E_OBJECT_NOT_FOUND,
1169 tr("Host network interface with UUID {%RTuuid} does not exist"),
1170 Guid (aId).raw());
1171 rc = iface->COMGETTER(Name)(name.asOutParam());
1172 ComAssertComRCRet(rc, rc);
1173 }
1174
1175 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, Guid(aId).ref(), aProgress);
1176 if (RT_SUCCESS(r))
1177 {
1178 /* Drop configuration parameters for removed interface */
1179 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress", name.raw()).raw(), NULL);
1180 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask", name.raw()).raw(), NULL);
1181 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address", name.raw()).raw(), NULL);
1182 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask", name.raw()).raw(), NULL);
1183
1184 return S_OK;
1185 }
1186
1187 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1188#else
1189 return E_NOTIMPL;
1190#endif
1191}
1192
1193STDMETHODIMP Host::CreateUSBDeviceFilter(IN_BSTR aName,
1194 IHostUSBDeviceFilter **aFilter)
1195{
1196#ifdef VBOX_WITH_USB
1197 CheckComArgStrNotEmptyOrNull(aName);
1198 CheckComArgOutPointerValid(aFilter);
1199
1200 AutoCaller autoCaller(this);
1201 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1202
1203 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1204
1205 ComObjPtr<HostUSBDeviceFilter> filter;
1206 filter.createObject();
1207 HRESULT rc = filter->init(this, aName);
1208 ComAssertComRCRet(rc, rc);
1209 rc = filter.queryInterfaceTo(aFilter);
1210 AssertComRCReturn(rc, rc);
1211 return S_OK;
1212#else
1213 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1214 * extended error info to indicate that USB is simply not available
1215 * (w/o treating it as a failure), for example, as in OSE. */
1216 NOREF(aName);
1217 NOREF(aFilter);
1218 ReturnComNotImplemented();
1219#endif
1220}
1221
1222STDMETHODIMP Host::InsertUSBDeviceFilter(ULONG aPosition,
1223 IHostUSBDeviceFilter *aFilter)
1224{
1225#ifdef VBOX_WITH_USB
1226 CheckComArgNotNull(aFilter);
1227
1228 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1229 AutoCaller autoCaller(this);
1230 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1231
1232 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1233
1234 clearError();
1235 MultiResult rc = checkUSBProxyService();
1236 if (FAILED(rc)) return rc;
1237
1238 ComObjPtr<HostUSBDeviceFilter> pFilter;
1239 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1240 it != m->llChildren.end();
1241 ++it)
1242 {
1243 if (*it == aFilter)
1244 {
1245 pFilter = *it;
1246 break;
1247 }
1248 }
1249 if (pFilter.isNull())
1250 return setError(VBOX_E_INVALID_OBJECT_STATE,
1251 tr("The given USB device filter is not created within this VirtualBox instance"));
1252
1253 if (pFilter->mInList)
1254 return setError(E_INVALIDARG,
1255 tr("The given USB device filter is already in the list"));
1256
1257 /* iterate to the position... */
1258 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1259 std::advance(itPos, aPosition);
1260 /* ...and insert */
1261 m->llUSBDeviceFilters.insert(itPos, pFilter);
1262 pFilter->mInList = true;
1263
1264 /* notify the proxy (only when the filter is active) */
1265 if ( m->pUSBProxyService->isActive()
1266 && pFilter->getData().mActive)
1267 {
1268 ComAssertRet(pFilter->getId() == NULL, E_FAIL);
1269 pFilter->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1270 }
1271
1272 // save the global settings; for that we should hold only the VirtualBox lock
1273 alock.release();
1274 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1275 return rc = m->pParent->saveSettings();
1276#else
1277 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1278 * extended error info to indicate that USB is simply not available
1279 * (w/o treating it as a failure), for example, as in OSE. */
1280 NOREF(aPosition);
1281 NOREF(aFilter);
1282 ReturnComNotImplemented();
1283#endif
1284}
1285
1286STDMETHODIMP Host::RemoveUSBDeviceFilter(ULONG aPosition)
1287{
1288#ifdef VBOX_WITH_USB
1289
1290 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1291 AutoCaller autoCaller(this);
1292 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1293
1294 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1295
1296 clearError();
1297 MultiResult rc = checkUSBProxyService();
1298 if (FAILED(rc)) return rc;
1299
1300 if (!m->llUSBDeviceFilters.size())
1301 return setError(E_INVALIDARG,
1302 tr("The USB device filter list is empty"));
1303
1304 if (aPosition >= m->llUSBDeviceFilters.size())
1305 return setError(E_INVALIDARG,
1306 tr("Invalid position: %lu (must be in range [0, %lu])"),
1307 aPosition, m->llUSBDeviceFilters.size() - 1);
1308
1309 ComObjPtr<HostUSBDeviceFilter> filter;
1310 {
1311 /* iterate to the position... */
1312 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1313 std::advance (it, aPosition);
1314 /* ...get an element from there... */
1315 filter = *it;
1316 /* ...and remove */
1317 filter->mInList = false;
1318 m->llUSBDeviceFilters.erase(it);
1319 }
1320
1321 /* notify the proxy (only when the filter is active) */
1322 if (m->pUSBProxyService->isActive() && filter->getData().mActive)
1323 {
1324 ComAssertRet(filter->getId() != NULL, E_FAIL);
1325 m->pUSBProxyService->removeFilter(filter->getId());
1326 filter->getId() = NULL;
1327 }
1328
1329 // save the global settings; for that we should hold only the VirtualBox lock
1330 alock.release();
1331 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1332 return rc = m->pParent->saveSettings();
1333#else
1334 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1335 * extended error info to indicate that USB is simply not available
1336 * (w/o treating it as a failure), for example, as in OSE. */
1337 NOREF(aPosition);
1338 ReturnComNotImplemented();
1339#endif
1340}
1341
1342STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IMedium **aDrive)
1343{
1344 CheckComArgStrNotEmptyOrNull(aName);
1345 CheckComArgOutPointerValid(aDrive);
1346
1347 ComObjPtr<Medium>medium;
1348 HRESULT rc = findHostDriveByNameOrId(DeviceType_DVD, Utf8Str(aName), medium);
1349 if (SUCCEEDED(rc))
1350 return medium.queryInterfaceTo(aDrive);
1351 else
1352 return setError(rc, Medium::tr("The host DVD drive named '%ls' could not be found"), aName);
1353}
1354
1355STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IMedium **aDrive)
1356{
1357 CheckComArgStrNotEmptyOrNull(aName);
1358 CheckComArgOutPointerValid(aDrive);
1359
1360 *aDrive = NULL;
1361
1362 ComObjPtr<Medium>medium;
1363 HRESULT rc = findHostDriveByNameOrId(DeviceType_Floppy, Utf8Str(aName), medium);
1364 if (SUCCEEDED(rc))
1365 return medium.queryInterfaceTo(aDrive);
1366 else
1367 return setError(rc, Medium::tr("The host floppy drive named '%ls' could not be found"), aName);
1368}
1369
1370STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
1371{
1372#ifndef VBOX_WITH_HOSTNETIF_API
1373 return E_NOTIMPL;
1374#else
1375 if (!name)
1376 return E_INVALIDARG;
1377 if (!networkInterface)
1378 return E_POINTER;
1379
1380 *networkInterface = NULL;
1381 ComObjPtr<HostNetworkInterface> found;
1382 std::list <ComObjPtr<HostNetworkInterface> > list;
1383 int rc = NetIfList(list);
1384 if (RT_FAILURE(rc))
1385 {
1386 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1387 return E_FAIL;
1388 }
1389 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1390 for (it = list.begin(); it != list.end(); ++it)
1391 {
1392 Bstr n;
1393 (*it)->COMGETTER(Name) (n.asOutParam());
1394 if (n == name)
1395 found = *it;
1396 }
1397
1398 if (!found)
1399 return setError(E_INVALIDARG,
1400 HostNetworkInterface::tr("The host network interface with the given name could not be found"));
1401
1402 found->setVirtualBox(m->pParent);
1403
1404 return found.queryInterfaceTo(networkInterface);
1405#endif
1406}
1407
1408STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
1409{
1410#ifndef VBOX_WITH_HOSTNETIF_API
1411 return E_NOTIMPL;
1412#else
1413 if (Guid(id).isEmpty())
1414 return E_INVALIDARG;
1415 if (!networkInterface)
1416 return E_POINTER;
1417
1418 *networkInterface = NULL;
1419 ComObjPtr<HostNetworkInterface> found;
1420 std::list <ComObjPtr<HostNetworkInterface> > list;
1421 int rc = NetIfList(list);
1422 if (RT_FAILURE(rc))
1423 {
1424 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1425 return E_FAIL;
1426 }
1427 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1428 for (it = list.begin(); it != list.end(); ++it)
1429 {
1430 Bstr g;
1431 (*it)->COMGETTER(Id) (g.asOutParam());
1432 if (g == id)
1433 found = *it;
1434 }
1435
1436 if (!found)
1437 return setError(E_INVALIDARG,
1438 HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
1439
1440 found->setVirtualBox(m->pParent);
1441
1442 return found.queryInterfaceTo(networkInterface);
1443#endif
1444}
1445
1446STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type,
1447 ComSafeArrayOut(IHostNetworkInterface *, aNetworkInterfaces))
1448{
1449#ifdef VBOX_WITH_HOSTNETIF_API
1450 std::list <ComObjPtr<HostNetworkInterface> > allList;
1451 int rc = NetIfList(allList);
1452 if (RT_FAILURE(rc))
1453 return E_FAIL;
1454
1455 std::list <ComObjPtr<HostNetworkInterface> > resultList;
1456
1457 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1458 for (it = allList.begin(); it != allList.end(); ++it)
1459 {
1460 HostNetworkInterfaceType_T t;
1461 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1462 if (FAILED(hr))
1463 return hr;
1464
1465 if (t == type)
1466 {
1467 (*it)->setVirtualBox(m->pParent);
1468 resultList.push_back (*it);
1469 }
1470 }
1471
1472 SafeIfaceArray<IHostNetworkInterface> filteredNetworkInterfaces (resultList);
1473 filteredNetworkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
1474
1475 return S_OK;
1476#else
1477 return E_NOTIMPL;
1478#endif
1479}
1480
1481STDMETHODIMP Host::FindUSBDeviceByAddress(IN_BSTR aAddress,
1482 IHostUSBDevice **aDevice)
1483{
1484#ifdef VBOX_WITH_USB
1485 CheckComArgStrNotEmptyOrNull(aAddress);
1486 CheckComArgOutPointerValid(aDevice);
1487
1488 *aDevice = NULL;
1489
1490 SafeIfaceArray<IHostUSBDevice> devsvec;
1491 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1492 if (FAILED(rc)) return rc;
1493
1494 for (size_t i = 0; i < devsvec.size(); ++i)
1495 {
1496 Bstr address;
1497 rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
1498 if (FAILED(rc)) return rc;
1499 if (address == aAddress)
1500 {
1501 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1502 }
1503 }
1504
1505 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1506 tr("Could not find a USB device with address '%ls'"),
1507 aAddress);
1508
1509#else /* !VBOX_WITH_USB */
1510 NOREF(aAddress);
1511 NOREF(aDevice);
1512 return E_NOTIMPL;
1513#endif /* !VBOX_WITH_USB */
1514}
1515
1516STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId,
1517 IHostUSBDevice **aDevice)
1518{
1519#ifdef VBOX_WITH_USB
1520 CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
1521 CheckComArgOutPointerValid(aDevice);
1522
1523 *aDevice = NULL;
1524
1525 SafeIfaceArray<IHostUSBDevice> devsvec;
1526 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1527 if (FAILED(rc)) return rc;
1528
1529 for (size_t i = 0; i < devsvec.size(); ++i)
1530 {
1531 Bstr id;
1532 rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
1533 if (FAILED(rc)) return rc;
1534 if (id == aId)
1535 {
1536 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1537 }
1538 }
1539
1540 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1541 "Could not find a USB device with uuid {%RTuuid}"),
1542 Guid (aId).raw());
1543
1544#else /* !VBOX_WITH_USB */
1545 NOREF(aId);
1546 NOREF(aDevice);
1547 return E_NOTIMPL;
1548#endif /* !VBOX_WITH_USB */
1549}
1550
1551STDMETHODIMP Host::GenerateMACAddress(BSTR *aAddress)
1552{
1553 CheckComArgOutPointerValid(aAddress);
1554 // no locking required
1555 Utf8Str mac;
1556 generateMACAddress(mac);
1557 Bstr(mac).cloneTo(aAddress);
1558 return S_OK;
1559}
1560
1561// public methods only for internal purposes
1562////////////////////////////////////////////////////////////////////////////////
1563
1564HRESULT Host::loadSettings(const settings::Host &data)
1565{
1566 HRESULT rc = S_OK;
1567#ifdef VBOX_WITH_USB
1568 AutoCaller autoCaller(this);
1569 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1570
1571 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1572
1573 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
1574 it != data.llUSBDeviceFilters.end();
1575 ++it)
1576 {
1577 const settings::USBDeviceFilter &f = *it;
1578 ComObjPtr<HostUSBDeviceFilter> pFilter;
1579 pFilter.createObject();
1580 rc = pFilter->init(this, f);
1581 if (FAILED(rc)) break;
1582
1583 m->llUSBDeviceFilters.push_back(pFilter);
1584 pFilter->mInList = true;
1585
1586 /* notify the proxy (only when the filter is active) */
1587 if (pFilter->getData().mActive)
1588 {
1589 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
1590 flt->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1591 }
1592 }
1593#else
1594 NOREF(data);
1595#endif /* VBOX_WITH_USB */
1596 return rc;
1597}
1598
1599HRESULT Host::saveSettings(settings::Host &data)
1600{
1601#ifdef VBOX_WITH_USB
1602 AutoCaller autoCaller(this);
1603 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1604
1605 AutoReadLock alock1(this COMMA_LOCKVAL_SRC_POS);
1606 AutoReadLock alock2(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1607
1608 data.llUSBDeviceFilters.clear();
1609
1610 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
1611 it != m->llUSBDeviceFilters.end();
1612 ++it)
1613 {
1614 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
1615 settings::USBDeviceFilter f;
1616 pFilter->saveSettings(f);
1617 data.llUSBDeviceFilters.push_back(f);
1618 }
1619#else
1620 NOREF(data);
1621#endif /* VBOX_WITH_USB */
1622
1623 return S_OK;
1624}
1625
1626/**
1627 * Sets the given pointer to point to the static list of DVD or floppy
1628 * drives in the Host instance data, depending on the @a mediumType
1629 * parameter.
1630 *
1631 * This builds the list on the first call; it adds or removes host drives
1632 * that may have changed if fRefresh == true.
1633 *
1634 * The caller must hold the medium tree write lock before calling this.
1635 * To protect the list to which the caller's pointer points, the caller
1636 * must also hold that lock.
1637 *
1638 * @param mediumType Must be DeviceType_Floppy or DeviceType_DVD.
1639 * @param fRefresh Whether to refresh the host drives list even if this is not the first call.
1640 * @param pll Caller's pointer which gets set to the static list of host drives.
1641 * @return
1642 */
1643HRESULT Host::getDrives(DeviceType_T mediumType,
1644 bool fRefresh,
1645 MediaList *&pll)
1646{
1647 HRESULT rc = S_OK;
1648 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1649
1650 MediaList llNew;
1651 MediaList *pllCached;
1652 bool *pfListBuilt = NULL;
1653
1654 switch (mediumType)
1655 {
1656 case DeviceType_DVD:
1657 if (!m->fDVDDrivesListBuilt || fRefresh)
1658 {
1659 rc = buildDVDDrivesList(llNew);
1660 if (FAILED(rc))
1661 return rc;
1662 pfListBuilt = &m->fDVDDrivesListBuilt;
1663 }
1664 pllCached = &m->llDVDDrives;
1665 break;
1666
1667 case DeviceType_Floppy:
1668 if (!m->fFloppyDrivesListBuilt || fRefresh)
1669 {
1670 rc = buildFloppyDrivesList(llNew);
1671 if (FAILED(rc))
1672 return rc;
1673 pfListBuilt = &m->fFloppyDrivesListBuilt;
1674 }
1675 pllCached = &m->llFloppyDrives;
1676 break;
1677
1678 default:
1679 return E_INVALIDARG;
1680 }
1681
1682 if (pfListBuilt)
1683 {
1684 // a list was built in llNew above:
1685 if (!*pfListBuilt)
1686 {
1687 // this was the first call (instance bool is still false): then just copy the whole list and return
1688 *pllCached = llNew;
1689 // and mark the instance data as "built"
1690 *pfListBuilt = true;
1691 }
1692 else
1693 {
1694 // list was built, and this was a subsequent call: then compare the old and the new lists
1695
1696 // remove drives from the cached list which are no longer present
1697 for (MediaList::iterator itCached = pllCached->begin();
1698 itCached != pllCached->end();
1699 /*nothing */)
1700 {
1701 Medium *pCached = *itCached;
1702 const Utf8Str strLocationCached = pCached->getLocationFull();
1703 bool fFound = false;
1704 for (MediaList::iterator itNew = llNew.begin();
1705 itNew != llNew.end();
1706 ++itNew)
1707 {
1708 Medium *pNew = *itNew;
1709 const Utf8Str strLocationNew = pNew->getLocationFull();
1710 if (strLocationNew == strLocationCached)
1711 {
1712 fFound = true;
1713 break;
1714 }
1715 }
1716 if (!fFound)
1717 itCached = pllCached->erase(itCached);
1718 else
1719 ++itCached;
1720 }
1721
1722 // add drives to the cached list that are not on there yet
1723 for (MediaList::iterator itNew = llNew.begin();
1724 itNew != llNew.end();
1725 ++itNew)
1726 {
1727 Medium *pNew = *itNew;
1728 const Utf8Str strLocationNew = pNew->getLocationFull();
1729 bool fFound = false;
1730 for (MediaList::iterator itCached = pllCached->begin();
1731 itCached != pllCached->end();
1732 ++itCached)
1733 {
1734 Medium *pCached = *itCached;
1735 const Utf8Str strLocationCached = pCached->getLocationFull();
1736 if (strLocationNew == strLocationCached)
1737 {
1738 fFound = true;
1739 break;
1740 }
1741 }
1742
1743 if (!fFound)
1744 pllCached->push_back(pNew);
1745 }
1746 }
1747 }
1748
1749 // return cached list to caller
1750 pll = pllCached;
1751
1752 return rc;
1753}
1754
1755/**
1756 * Goes through the list of host drives that would be returned by getDrives()
1757 * and looks for a host drive with the given UUID. If found, it sets pMedium
1758 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1759 *
1760 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1761 * @param uuid Medium UUID of host drive to look for.
1762 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1763 * @param pMedium Medium object, if found…
1764 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1765 */
1766HRESULT Host::findHostDriveById(DeviceType_T mediumType,
1767 const Guid &uuid,
1768 bool fRefresh,
1769 ComObjPtr<Medium> &pMedium)
1770{
1771 MediaList *pllMedia;
1772
1773 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1774 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1775 if (SUCCEEDED(rc))
1776 {
1777 for (MediaList::iterator it = pllMedia->begin();
1778 it != pllMedia->end();
1779 ++it)
1780 {
1781 Medium *pThis = *it;
1782 AutoCaller mediumCaller(pThis);
1783 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1784 if (pThis->getId() == uuid)
1785 {
1786 pMedium = pThis;
1787 return S_OK;
1788 }
1789 }
1790 }
1791
1792 return VBOX_E_OBJECT_NOT_FOUND;
1793}
1794
1795/**
1796 * Goes through the list of host drives that would be returned by getDrives()
1797 * and looks for a host drive with the given name. If found, it sets pMedium
1798 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1799 *
1800 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1801 * @param strLocationFull Name (path) of host drive to look for.
1802 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1803 * @param pMedium Medium object, if found…
1804 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1805 */
1806HRESULT Host::findHostDriveByName(DeviceType_T mediumType,
1807 const Utf8Str &strLocationFull,
1808 bool fRefresh,
1809 ComObjPtr<Medium> &pMedium)
1810{
1811 MediaList *pllMedia;
1812
1813 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1814 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1815 if (SUCCEEDED(rc))
1816 {
1817 for (MediaList::iterator it = pllMedia->begin();
1818 it != pllMedia->end();
1819 ++it)
1820 {
1821 Medium *pThis = *it;
1822 AutoCaller mediumCaller(pThis);
1823 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1824 if (pThis->getLocationFull() == strLocationFull)
1825 {
1826 pMedium = pThis;
1827 return S_OK;
1828 }
1829 }
1830 }
1831
1832 return VBOX_E_OBJECT_NOT_FOUND;
1833}
1834
1835/**
1836 * Goes through the list of host drives that would be returned by getDrives()
1837 * and looks for a host drive with the given name, location or ID. If found,
1838 * it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1839 *
1840 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1841 * @param strNameOrId Name or full location or UUID of host drive to look for.
1842 * @param pMedium Medium object, if found…
1843 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1844 */
1845HRESULT Host::findHostDriveByNameOrId(DeviceType_T mediumType,
1846 const Utf8Str &strNameOrId,
1847 ComObjPtr<Medium> &pMedium)
1848{
1849 AutoWriteLock wlock(m->pParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
1850
1851 Guid uuid(strNameOrId);
1852 if (!uuid.isEmpty())
1853 return findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
1854
1855 // string is not a syntactically valid UUID: try a name then
1856 return findHostDriveByName(mediumType, strNameOrId, true /* fRefresh */, pMedium);
1857}
1858
1859/**
1860 * Called from getDrives() to build the DVD drives list.
1861 * @param pll
1862 * @return
1863 */
1864HRESULT Host::buildDVDDrivesList(MediaList &list)
1865{
1866 HRESULT rc = S_OK;
1867
1868 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1869
1870 try
1871 {
1872#if defined(RT_OS_WINDOWS)
1873 int sz = GetLogicalDriveStrings(0, NULL);
1874 TCHAR *hostDrives = new TCHAR[sz+1];
1875 GetLogicalDriveStrings(sz, hostDrives);
1876 wchar_t driveName[3] = { '?', ':', '\0' };
1877 TCHAR *p = hostDrives;
1878 do
1879 {
1880 if (GetDriveType(p) == DRIVE_CDROM)
1881 {
1882 driveName[0] = *p;
1883 ComObjPtr<Medium> hostDVDDriveObj;
1884 hostDVDDriveObj.createObject();
1885 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
1886 list.push_back(hostDVDDriveObj);
1887 }
1888 p += _tcslen(p) + 1;
1889 }
1890 while (*p);
1891 delete[] hostDrives;
1892
1893#elif defined(RT_OS_SOLARIS)
1894# ifdef VBOX_USE_LIBHAL
1895 if (!getDVDInfoFromHal(list))
1896# endif
1897 {
1898 getDVDInfoFromDevTree(list);
1899 }
1900
1901#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
1902 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
1903 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
1904 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
1905 {
1906 ComObjPtr<Medium> hostDVDDriveObj;
1907 Utf8Str location(it->mDevice);
1908 Utf8Str description(it->mDescription);
1909 if (SUCCEEDED(rc))
1910 rc = hostDVDDriveObj.createObject();
1911 if (SUCCEEDED(rc))
1912 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
1913 if (SUCCEEDED(rc))
1914 list.push_back(hostDVDDriveObj);
1915 }
1916#elif defined(RT_OS_DARWIN)
1917 PDARWINDVD cur = DarwinGetDVDDrives();
1918 while (cur)
1919 {
1920 ComObjPtr<Medium> hostDVDDriveObj;
1921 hostDVDDriveObj.createObject();
1922 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
1923 list.push_back(hostDVDDriveObj);
1924
1925 /* next */
1926 void *freeMe = cur;
1927 cur = cur->pNext;
1928 RTMemFree(freeMe);
1929 }
1930#else
1931 /* PORTME */
1932#endif
1933 }
1934 catch(std::bad_alloc &)
1935 {
1936 rc = E_OUTOFMEMORY;
1937 }
1938 return rc;
1939}
1940
1941/**
1942 * Called from getDrives() to build the floppy drives list.
1943 * @param list
1944 * @return
1945 */
1946HRESULT Host::buildFloppyDrivesList(MediaList &list)
1947{
1948 HRESULT rc = S_OK;
1949
1950 Assert(m->pParent->getMediaTreeLockHandle().isWriteLockOnCurrentThread());
1951
1952 try
1953 {
1954#ifdef RT_OS_WINDOWS
1955 int sz = GetLogicalDriveStrings(0, NULL);
1956 TCHAR *hostDrives = new TCHAR[sz+1];
1957 GetLogicalDriveStrings(sz, hostDrives);
1958 wchar_t driveName[3] = { '?', ':', '\0' };
1959 TCHAR *p = hostDrives;
1960 do
1961 {
1962 if (GetDriveType(p) == DRIVE_REMOVABLE)
1963 {
1964 driveName[0] = *p;
1965 ComObjPtr<Medium> hostFloppyDriveObj;
1966 hostFloppyDriveObj.createObject();
1967 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
1968 list.push_back(hostFloppyDriveObj);
1969 }
1970 p += _tcslen(p) + 1;
1971 }
1972 while (*p);
1973 delete[] hostDrives;
1974#elif defined(RT_OS_LINUX)
1975 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
1976 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
1977 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
1978 {
1979 ComObjPtr<Medium> hostFloppyDriveObj;
1980 Utf8Str location(it->mDevice);
1981 Utf8Str description(it->mDescription);
1982 if (SUCCEEDED(rc))
1983 rc = hostFloppyDriveObj.createObject();
1984 if (SUCCEEDED(rc))
1985 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
1986 if (SUCCEEDED(rc))
1987 list.push_back(hostFloppyDriveObj);
1988 }
1989#else
1990 NOREF(list);
1991 /* PORTME */
1992#endif
1993 }
1994 catch(std::bad_alloc &)
1995 {
1996 rc = E_OUTOFMEMORY;
1997 }
1998
1999 return rc;
2000}
2001
2002#ifdef VBOX_WITH_USB
2003USBProxyService* Host::usbProxyService()
2004{
2005 return m->pUSBProxyService;
2006}
2007
2008HRESULT Host::addChild(HostUSBDeviceFilter *pChild)
2009{
2010 AutoCaller autoCaller(this);
2011 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2012
2013 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
2014
2015 m->llChildren.push_back(pChild);
2016
2017 return S_OK;
2018}
2019
2020HRESULT Host::removeChild(HostUSBDeviceFilter *pChild)
2021{
2022 AutoCaller autoCaller(this);
2023 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2024
2025 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
2026
2027 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
2028 it != m->llChildren.end();
2029 ++it)
2030 {
2031 if (*it == pChild)
2032 {
2033 m->llChildren.erase(it);
2034 break;
2035 }
2036 }
2037
2038 return S_OK;
2039}
2040
2041VirtualBox* Host::parent()
2042{
2043 return m->pParent;
2044}
2045
2046/**
2047 * Called by setter methods of all USB device filters.
2048 */
2049HRESULT Host::onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
2050 BOOL aActiveChanged /* = FALSE */)
2051{
2052 AutoCaller autoCaller(this);
2053 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2054
2055 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2056
2057 if (aFilter->mInList)
2058 {
2059 if (aActiveChanged)
2060 {
2061 // insert/remove the filter from the proxy
2062 if (aFilter->getData().mActive)
2063 {
2064 ComAssertRet(aFilter->getId() == NULL, E_FAIL);
2065 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2066 }
2067 else
2068 {
2069 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2070 m->pUSBProxyService->removeFilter(aFilter->getId());
2071 aFilter->getId() = NULL;
2072 }
2073 }
2074 else
2075 {
2076 if (aFilter->getData().mActive)
2077 {
2078 // update the filter in the proxy
2079 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2080 m->pUSBProxyService->removeFilter(aFilter->getId());
2081 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2082 }
2083 }
2084
2085 // save the global settings... yeah, on every single filter property change
2086 // for that we should hold only the VirtualBox lock
2087 alock.release();
2088 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
2089 return m->pParent->saveSettings();
2090 }
2091
2092 return S_OK;
2093}
2094
2095
2096/**
2097 * Interface for obtaining a copy of the USBDeviceFilterList,
2098 * used by the USBProxyService.
2099 *
2100 * @param aGlobalFilters Where to put the global filter list copy.
2101 * @param aMachines Where to put the machine vector.
2102 */
2103void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
2104{
2105 AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
2106
2107 *aGlobalFilters = m->llUSBDeviceFilters;
2108}
2109
2110#endif /* VBOX_WITH_USB */
2111
2112// private methods
2113////////////////////////////////////////////////////////////////////////////////
2114
2115#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
2116
2117/**
2118 * Helper function to get the slice number from a device path
2119 *
2120 * @param pszDevLinkPath Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
2121 * @returns Pointer to the slice portion of the given path.
2122 */
2123static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
2124{
2125 char *pszFound = NULL;
2126 char *pszSlice = strrchr(pszDevLinkPath, 's');
2127 char *pszDisk = strrchr(pszDevLinkPath, 'd');
2128 if (pszSlice && pszSlice > pszDisk)
2129 pszFound = pszSlice;
2130 else
2131 pszFound = pszDisk;
2132
2133 if (pszFound && RT_C_IS_DIGIT(pszFound[1]))
2134 return pszFound;
2135
2136 return NULL;
2137}
2138
2139/**
2140 * Walk device links and returns an allocated path for the first one in the snapshot.
2141 *
2142 * @param DevLink Handle to the device link being walked.
2143 * @param pvArg Opaque data containing the pointer to the path.
2144 * @returns Pointer to an allocated device path string.
2145 */
2146static int solarisWalkDevLink(di_devlink_t DevLink, void *pvArg)
2147{
2148 char **ppszPath = (char **)pvArg;
2149 *ppszPath = strdup(di_devlink_path(DevLink));
2150 return DI_WALK_TERMINATE;
2151}
2152
2153/**
2154 * Walk all devices in the system and enumerate CD/DVD drives.
2155 * @param Node Handle to the current node.
2156 * @param pvArg Opaque data (holds list pointer).
2157 * @returns Solaris specific code whether to continue walking or not.
2158 */
2159static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
2160{
2161 PSOLARISDVD *ppDrives = (PSOLARISDVD *)pvArg;
2162
2163 /*
2164 * Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
2165 * As unfortunately the Solaris drivers only export these common properties.
2166 */
2167 int *pInt = NULL;
2168 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "removable-media", &pInt) >= 0
2169 || di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "hotpluggable", &pInt) >= 0)
2170 {
2171 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2172 && ( *pInt == DTYPE_RODIRECT /* CDROM */
2173 || *pInt == DTYPE_OPTICAL)) /* Optical Drive */
2174 {
2175 char *pszProduct = NULL;
2176 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2177 {
2178 char *pszVendor = NULL;
2179 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2180 {
2181 /*
2182 * Found a DVD drive, we need to scan the minor nodes to find the correct
2183 * slice that represents the whole drive. "s2" is always the whole drive for CD/DVDs.
2184 */
2185 int Major = di_driver_major(Node);
2186 di_minor_t Minor = DI_MINOR_NIL;
2187 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2188 if (DevLink)
2189 {
2190 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2191 {
2192 dev_t Dev = di_minor_devt(Minor);
2193 if ( Major != (int)major(Dev)
2194 || di_minor_spectype(Minor) == S_IFBLK
2195 || di_minor_type(Minor) != DDM_MINOR)
2196 {
2197 continue;
2198 }
2199
2200 char *pszMinorPath = di_devfs_minor_path(Minor);
2201 if (!pszMinorPath)
2202 continue;
2203
2204 char *pszDevLinkPath = NULL;
2205 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2206 di_devfs_path_free(pszMinorPath);
2207
2208 if (pszDevLinkPath)
2209 {
2210 char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
2211 if ( pszSlice && !strcmp(pszSlice, "s2")
2212 && !strncmp(pszDevLinkPath, "/dev/rdsk", sizeof("/dev/rdsk") - 1)) /* We want only raw disks */
2213 {
2214 /*
2215 * We've got a fully qualified DVD drive. Add it to the list.
2216 */
2217 PSOLARISDVD pDrive = (PSOLARISDVD)RTMemAllocZ(sizeof(SOLARISDVD));
2218 if (RT_LIKELY(pDrive))
2219 {
2220 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription), "%s %s", pszVendor, pszProduct);
2221 RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevLinkPath);
2222 if (*ppDrives)
2223 pDrive->pNext = *ppDrives;
2224 *ppDrives = pDrive;
2225
2226 /* We're not interested in any of the other slices, stop minor nodes traversal. */
2227 free(pszDevLinkPath);
2228 break;
2229 }
2230 }
2231 free(pszDevLinkPath);
2232 }
2233 }
2234 di_devlink_fini(&DevLink);
2235 }
2236 }
2237 }
2238 }
2239 }
2240 return DI_WALK_CONTINUE;
2241}
2242
2243/**
2244 * Solaris specific function to enumerate CD/DVD drives via the device tree.
2245 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2246 */
2247void Host::getDVDInfoFromDevTree(std::list<ComObjPtr<Medium> > &list)
2248{
2249 PSOLARISDVD pDrives = NULL;
2250 di_node_t RootNode = di_init("/", DINFOCPYALL);
2251 if (RootNode != DI_NODE_NIL)
2252 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForDVD);
2253
2254 di_fini(RootNode);
2255
2256 while (pDrives)
2257 {
2258 ComObjPtr<Medium> hostDVDDriveObj;
2259 hostDVDDriveObj.createObject();
2260 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
2261 list.push_back(hostDVDDriveObj);
2262
2263 void *pvDrive = pDrives;
2264 pDrives = pDrives->pNext;
2265 RTMemFree(pvDrive);
2266 }
2267}
2268
2269/* Solaris hosts, loading libhal at runtime */
2270
2271/**
2272 * Helper function to query the hal subsystem for information about DVD drives attached to the
2273 * system.
2274 *
2275 * @returns true if information was successfully obtained, false otherwise
2276 * @retval list drives found will be attached to this list
2277 */
2278bool Host::getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
2279{
2280 bool halSuccess = false;
2281 DBusError dbusError;
2282 if (!gLibHalCheckPresence())
2283 return false;
2284 gDBusErrorInit (&dbusError);
2285 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2286 if (dbusConnection != 0)
2287 {
2288 LibHalContext *halContext = gLibHalCtxNew();
2289 if (halContext != 0)
2290 {
2291 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2292 {
2293 if (gLibHalCtxInit(halContext, &dbusError))
2294 {
2295 int numDevices;
2296 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2297 "storage.drive_type", "cdrom",
2298 &numDevices, &dbusError);
2299 if (halDevices != 0)
2300 {
2301 /* Hal is installed and working, so if no devices are reported, assume
2302 that there are none. */
2303 halSuccess = true;
2304 for (int i = 0; i < numDevices; i++)
2305 {
2306 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2307 halDevices[i], "block.device", &dbusError);
2308#ifdef RT_OS_SOLARIS
2309 /* The CD/DVD ioctls work only for raw device nodes. */
2310 char *tmp = getfullrawname(devNode);
2311 gLibHalFreeString(devNode);
2312 devNode = tmp;
2313#endif
2314
2315 if (devNode != 0)
2316 {
2317// if (validateDevice(devNode, true))
2318// {
2319 Utf8Str description;
2320 char *vendor, *product;
2321 /* We do not check the error here, as this field may
2322 not even exist. */
2323 vendor = gLibHalDeviceGetPropertyString(halContext,
2324 halDevices[i], "info.vendor", 0);
2325 product = gLibHalDeviceGetPropertyString(halContext,
2326 halDevices[i], "info.product", &dbusError);
2327 if ((product != 0 && product[0] != 0))
2328 {
2329 if ((vendor != 0) && (vendor[0] != 0))
2330 {
2331 description = Utf8StrFmt ("%s %s",
2332 vendor, product);
2333 }
2334 else
2335 {
2336 description = product;
2337 }
2338 ComObjPtr<Medium> hostDVDDriveObj;
2339 hostDVDDriveObj.createObject();
2340 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2341 Bstr(devNode), Bstr(description));
2342 list.push_back (hostDVDDriveObj);
2343 }
2344 else
2345 {
2346 if (product == 0)
2347 {
2348 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2349 halDevices[i], dbusError.name, dbusError.message));
2350 gDBusErrorFree(&dbusError);
2351 }
2352 ComObjPtr<Medium> hostDVDDriveObj;
2353 hostDVDDriveObj.createObject();
2354 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2355 Bstr(devNode));
2356 list.push_back (hostDVDDriveObj);
2357 }
2358 if (vendor != 0)
2359 {
2360 gLibHalFreeString(vendor);
2361 }
2362 if (product != 0)
2363 {
2364 gLibHalFreeString(product);
2365 }
2366// }
2367// else
2368// {
2369// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
2370// }
2371#ifndef RT_OS_SOLARIS
2372 gLibHalFreeString(devNode);
2373#else
2374 free(devNode);
2375#endif
2376 }
2377 else
2378 {
2379 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2380 halDevices[i], dbusError.name, dbusError.message));
2381 gDBusErrorFree(&dbusError);
2382 }
2383 }
2384 gLibHalFreeStringArray(halDevices);
2385 }
2386 else
2387 {
2388 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2389 gDBusErrorFree(&dbusError);
2390 }
2391 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2392 {
2393 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2394 gDBusErrorFree(&dbusError);
2395 }
2396 }
2397 else
2398 {
2399 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2400 gDBusErrorFree(&dbusError);
2401 }
2402 gLibHalCtxFree(halContext);
2403 }
2404 else
2405 {
2406 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
2407 }
2408 }
2409 else
2410 {
2411 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
2412 }
2413 gDBusConnectionUnref(dbusConnection);
2414 }
2415 else
2416 {
2417 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2418 gDBusErrorFree(&dbusError);
2419 }
2420 return halSuccess;
2421}
2422
2423
2424/**
2425 * Helper function to query the hal subsystem for information about floppy drives attached to the
2426 * system.
2427 *
2428 * @returns true if information was successfully obtained, false otherwise
2429 * @retval list drives found will be attached to this list
2430 */
2431bool Host::getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
2432{
2433 bool halSuccess = false;
2434 DBusError dbusError;
2435 if (!gLibHalCheckPresence())
2436 return false;
2437 gDBusErrorInit (&dbusError);
2438 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2439 if (dbusConnection != 0)
2440 {
2441 LibHalContext *halContext = gLibHalCtxNew();
2442 if (halContext != 0)
2443 {
2444 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2445 {
2446 if (gLibHalCtxInit(halContext, &dbusError))
2447 {
2448 int numDevices;
2449 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2450 "storage.drive_type", "floppy",
2451 &numDevices, &dbusError);
2452 if (halDevices != 0)
2453 {
2454 /* Hal is installed and working, so if no devices are reported, assume
2455 that there are none. */
2456 halSuccess = true;
2457 for (int i = 0; i < numDevices; i++)
2458 {
2459 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2460 halDevices[i], "storage.drive_type", 0);
2461 if (driveType != 0)
2462 {
2463 if (strcmp(driveType, "floppy") != 0)
2464 {
2465 gLibHalFreeString(driveType);
2466 continue;
2467 }
2468 gLibHalFreeString(driveType);
2469 }
2470 else
2471 {
2472 /* An error occurred. The attribute "storage.drive_type"
2473 probably didn't exist. */
2474 continue;
2475 }
2476 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2477 halDevices[i], "block.device", &dbusError);
2478 if (devNode != 0)
2479 {
2480// if (validateDevice(devNode, false))
2481// {
2482 Utf8Str description;
2483 char *vendor, *product;
2484 /* We do not check the error here, as this field may
2485 not even exist. */
2486 vendor = gLibHalDeviceGetPropertyString(halContext,
2487 halDevices[i], "info.vendor", 0);
2488 product = gLibHalDeviceGetPropertyString(halContext,
2489 halDevices[i], "info.product", &dbusError);
2490 if ((product != 0) && (product[0] != 0))
2491 {
2492 if ((vendor != 0) && (vendor[0] != 0))
2493 {
2494 description = Utf8StrFmt ("%s %s",
2495 vendor, product);
2496 }
2497 else
2498 {
2499 description = product;
2500 }
2501 ComObjPtr<Medium> hostFloppyDrive;
2502 hostFloppyDrive.createObject();
2503 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2504 Bstr(devNode), Bstr(description));
2505 list.push_back (hostFloppyDrive);
2506 }
2507 else
2508 {
2509 if (product == 0)
2510 {
2511 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2512 halDevices[i], dbusError.name, dbusError.message));
2513 gDBusErrorFree(&dbusError);
2514 }
2515 ComObjPtr<Medium> hostFloppyDrive;
2516 hostFloppyDrive.createObject();
2517 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2518 Bstr(devNode));
2519 list.push_back (hostFloppyDrive);
2520 }
2521 if (vendor != 0)
2522 {
2523 gLibHalFreeString(vendor);
2524 }
2525 if (product != 0)
2526 {
2527 gLibHalFreeString(product);
2528 }
2529// }
2530// else
2531// {
2532// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2533// }
2534 gLibHalFreeString(devNode);
2535 }
2536 else
2537 {
2538 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2539 halDevices[i], dbusError.name, dbusError.message));
2540 gDBusErrorFree(&dbusError);
2541 }
2542 }
2543 gLibHalFreeStringArray(halDevices);
2544 }
2545 else
2546 {
2547 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2548 gDBusErrorFree(&dbusError);
2549 }
2550 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2551 {
2552 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2553 gDBusErrorFree(&dbusError);
2554 }
2555 }
2556 else
2557 {
2558 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2559 gDBusErrorFree(&dbusError);
2560 }
2561 gLibHalCtxFree(halContext);
2562 }
2563 else
2564 {
2565 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2566 }
2567 }
2568 else
2569 {
2570 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2571 }
2572 gDBusConnectionUnref(dbusConnection);
2573 }
2574 else
2575 {
2576 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2577 gDBusErrorFree(&dbusError);
2578 }
2579 return halSuccess;
2580}
2581#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2582
2583/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
2584#if defined(RT_OS_SOLARIS)
2585
2586/**
2587 * Helper function to parse the given mount file and add found entries
2588 */
2589void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
2590{
2591#ifdef RT_OS_LINUX
2592 FILE *mtab = setmntent(mountTable, "r");
2593 if (mtab)
2594 {
2595 struct mntent *mntent;
2596 char *mnt_type;
2597 char *mnt_dev;
2598 char *tmp;
2599 while ((mntent = getmntent(mtab)))
2600 {
2601 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2602 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2603 strcpy(mnt_type, mntent->mnt_type);
2604 strcpy(mnt_dev, mntent->mnt_fsname);
2605 // supermount fs case
2606 if (strcmp(mnt_type, "supermount") == 0)
2607 {
2608 tmp = strstr(mntent->mnt_opts, "fs=");
2609 if (tmp)
2610 {
2611 free(mnt_type);
2612 mnt_type = strdup(tmp + strlen("fs="));
2613 if (mnt_type)
2614 {
2615 tmp = strchr(mnt_type, ',');
2616 if (tmp)
2617 *tmp = '\0';
2618 }
2619 }
2620 tmp = strstr(mntent->mnt_opts, "dev=");
2621 if (tmp)
2622 {
2623 free(mnt_dev);
2624 mnt_dev = strdup(tmp + strlen("dev="));
2625 if (mnt_dev)
2626 {
2627 tmp = strchr(mnt_dev, ',');
2628 if (tmp)
2629 *tmp = '\0';
2630 }
2631 }
2632 }
2633 // use strstr here to cover things fs types like "udf,iso9660"
2634 if (strstr(mnt_type, "iso9660") == 0)
2635 {
2636 /** @todo check whether we've already got the drive in our list! */
2637 if (validateDevice(mnt_dev, true))
2638 {
2639 ComObjPtr<Medium> hostDVDDriveObj;
2640 hostDVDDriveObj.createObject();
2641 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
2642 list.push_back (hostDVDDriveObj);
2643 }
2644 }
2645 free(mnt_dev);
2646 free(mnt_type);
2647 }
2648 endmntent(mtab);
2649 }
2650#else // RT_OS_SOLARIS
2651 FILE *mntFile = fopen(mountTable, "r");
2652 if (mntFile)
2653 {
2654 struct mnttab mntTab;
2655 while (getmntent(mntFile, &mntTab) == 0)
2656 {
2657 const char *mountName = mntTab.mnt_special;
2658 const char *mountPoint = mntTab.mnt_mountp;
2659 const char *mountFSType = mntTab.mnt_fstype;
2660 if (mountName && mountPoint && mountFSType)
2661 {
2662 // skip devices we are not interested in
2663 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2664 (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 && // skip devfs (i.e. /devices)
2665 strncmp(mountFSType, "dev", 3) != 0 && // skip dev (i.e. /dev)
2666 strncmp(mountFSType, "lofs", 4) != 0))) // skip loop-back file-system (lofs)
2667 {
2668 char *rawDevName = getfullrawname((char *)mountName);
2669 if (validateDevice(rawDevName, true))
2670 {
2671 ComObjPtr<Medium> hostDVDDriveObj;
2672 hostDVDDriveObj.createObject();
2673 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
2674 list.push_back (hostDVDDriveObj);
2675 }
2676 free(rawDevName);
2677 }
2678 }
2679 }
2680
2681 fclose(mntFile);
2682 }
2683#endif
2684}
2685
2686/**
2687 * Helper function to check whether the given device node is a valid drive
2688 */
2689bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2690{
2691 struct stat statInfo;
2692 bool retValue = false;
2693
2694 // sanity check
2695 if (!deviceNode)
2696 {
2697 return false;
2698 }
2699
2700 // first a simple stat() call
2701 if (stat(deviceNode, &statInfo) < 0)
2702 {
2703 return false;
2704 }
2705 else
2706 {
2707 if (isCDROM)
2708 {
2709 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2710 {
2711 int fileHandle;
2712 // now try to open the device
2713 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2714 if (fileHandle >= 0)
2715 {
2716 cdrom_subchnl cdChannelInfo;
2717 cdChannelInfo.cdsc_format = CDROM_MSF;
2718 // this call will finally reveal the whole truth
2719#ifdef RT_OS_LINUX
2720 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2721 (errno == EIO) || (errno == ENOENT) ||
2722 (errno == EINVAL) || (errno == ENOMEDIUM))
2723#else
2724 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2725 (errno == EIO) || (errno == ENOENT) ||
2726 (errno == EINVAL))
2727#endif
2728 {
2729 retValue = true;
2730 }
2731 close(fileHandle);
2732 }
2733 }
2734 } else
2735 {
2736 // floppy case
2737 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2738 {
2739 /// @todo do some more testing, maybe a nice IOCTL!
2740 retValue = true;
2741 }
2742 }
2743 }
2744 return retValue;
2745}
2746#endif // RT_OS_SOLARIS
2747
2748#ifdef VBOX_WITH_USB
2749/**
2750 * Checks for the presence and status of the USB Proxy Service.
2751 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2752 * warning) if the proxy service is not available due to the way the host is
2753 * configured (at present, that means that usbfs and hal/DBus are not
2754 * available on a Linux host) or E_FAIL and a corresponding error message
2755 * otherwise. Intended to be used by methods that rely on the Proxy Service
2756 * availability.
2757 *
2758 * @note This method may return a warning result code. It is recommended to use
2759 * MultiError to store the return value.
2760 *
2761 * @note Locks this object for reading.
2762 */
2763HRESULT Host::checkUSBProxyService()
2764{
2765 AutoCaller autoCaller(this);
2766 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2767
2768 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2769
2770 AssertReturn(m->pUSBProxyService, E_FAIL);
2771 if (!m->pUSBProxyService->isActive())
2772 {
2773 /* disable the USB controller completely to avoid assertions if the
2774 * USB proxy service could not start. */
2775
2776 switch (m->pUSBProxyService->getLastError())
2777 {
2778 case VERR_FILE_NOT_FOUND: /** @todo what does this mean? */
2779 return setWarning(E_FAIL,
2780 tr("Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer"));
2781 case VERR_VUSB_USB_DEVICE_PERMISSION:
2782 return setWarning(E_FAIL,
2783 tr("VirtualBox is not currently allowed to access USB devices. You can change this by adding your user to the 'vboxusers' group. Please see the user manual for a more detailed explanation"));
2784 case VERR_VUSB_USBFS_PERMISSION:
2785 return setWarning(E_FAIL,
2786 tr("VirtualBox is not currently allowed to access USB devices. You can change this by allowing your user to access the 'usbfs' folder and files. Please see the user manual for a more detailed explanation"));
2787 case VINF_SUCCESS:
2788 return setWarning(E_FAIL,
2789 tr("The USB Proxy Service has not yet been ported to this host"));
2790 default:
2791 return setWarning (E_FAIL, "%s: %Rrc",
2792 tr ("Could not load the Host USB Proxy service"),
2793 m->pUSBProxyService->getLastError());
2794 }
2795 }
2796
2797 return S_OK;
2798}
2799#endif /* VBOX_WITH_USB */
2800
2801#ifdef VBOX_WITH_RESOURCE_USAGE_API
2802
2803void Host::registerMetrics(PerformanceCollector *aCollector)
2804{
2805 pm::CollectorHAL *hal = aCollector->getHAL();
2806 /* Create sub metrics */
2807 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
2808 "Percentage of processor time spent in user mode.");
2809 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
2810 "Percentage of processor time spent in kernel mode.");
2811 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
2812 "Percentage of processor time spent idling.");
2813 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
2814 "Average of current frequency of all processors.");
2815 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
2816 "Total physical memory installed.");
2817 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
2818 "Physical memory currently occupied.");
2819 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
2820 "Physical memory currently available to applications.");
2821 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
2822 "Total physical memory used by the hypervisor.");
2823 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
2824 "Total physical memory free inside the hypervisor.");
2825 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
2826 "Total physical memory ballooned by the hypervisor.");
2827 pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
2828 "Total physical memory shared between VMs.");
2829
2830
2831 /* Create and register base metrics */
2832 IUnknown *objptr;
2833 ComObjPtr<Host> tmp = this;
2834 tmp.queryInterfaceTo(&objptr);
2835 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, objptr, cpuLoadUser, cpuLoadKernel,
2836 cpuLoadIdle);
2837 aCollector->registerBaseMetric (cpuLoad);
2838 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, objptr, cpuMhzSM);
2839 aCollector->registerBaseMetric (cpuMhz);
2840 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, objptr,
2841 ramUsageTotal,
2842 ramUsageUsed,
2843 ramUsageFree);
2844 aCollector->registerBaseMetric (ramUsage);
2845 pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), objptr,
2846 ramVMMUsed,
2847 ramVMMFree,
2848 ramVMMBallooned,
2849 ramVMMShared);
2850 aCollector->registerBaseMetric (ramVmm);
2851
2852 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
2853 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2854 new pm::AggregateAvg()));
2855 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2856 new pm::AggregateMin()));
2857 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2858 new pm::AggregateMax()));
2859
2860 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
2861 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2862 new pm::AggregateAvg()));
2863 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2864 new pm::AggregateMin()));
2865 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2866 new pm::AggregateMax()));
2867
2868 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
2869 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2870 new pm::AggregateAvg()));
2871 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2872 new pm::AggregateMin()));
2873 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2874 new pm::AggregateMax()));
2875
2876 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
2877 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2878 new pm::AggregateAvg()));
2879 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2880 new pm::AggregateMin()));
2881 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2882 new pm::AggregateMax()));
2883
2884 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
2885 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2886 new pm::AggregateAvg()));
2887 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2888 new pm::AggregateMin()));
2889 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2890 new pm::AggregateMax()));
2891
2892 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
2893 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2894 new pm::AggregateAvg()));
2895 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2896 new pm::AggregateMin()));
2897 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2898 new pm::AggregateMax()));
2899
2900 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
2901 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2902 new pm::AggregateAvg()));
2903 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2904 new pm::AggregateMin()));
2905 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2906 new pm::AggregateMax()));
2907
2908 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed, 0));
2909 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2910 new pm::AggregateAvg()));
2911 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2912 new pm::AggregateMin()));
2913 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2914 new pm::AggregateMax()));
2915
2916 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree, 0));
2917 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2918 new pm::AggregateAvg()));
2919 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2920 new pm::AggregateMin()));
2921 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2922 new pm::AggregateMax()));
2923
2924 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned, 0));
2925 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2926 new pm::AggregateAvg()));
2927 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2928 new pm::AggregateMin()));
2929 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2930 new pm::AggregateMax()));
2931
2932 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared, 0));
2933 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2934 new pm::AggregateAvg()));
2935 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2936 new pm::AggregateMin()));
2937 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2938 new pm::AggregateMax()));
2939}
2940
2941void Host::unregisterMetrics (PerformanceCollector *aCollector)
2942{
2943 aCollector->unregisterMetricsFor(this);
2944 aCollector->unregisterBaseMetricsFor(this);
2945}
2946
2947
2948/* static */
2949void Host::generateMACAddress(Utf8Str &mac)
2950{
2951 /*
2952 * Our strategy is as follows: the first three bytes are our fixed
2953 * vendor ID (080027). The remaining 3 bytes will be taken from the
2954 * start of a GUID. This is a fairly safe algorithm.
2955 */
2956 Guid guid;
2957 guid.create();
2958 mac = Utf8StrFmt("080027%02X%02X%02X",
2959 guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
2960}
2961
2962#endif /* VBOX_WITH_RESOURCE_USAGE_API */
2963
2964/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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