VirtualBox

source: vbox/trunk/src/VBox/Main/HostImpl.cpp@ 28036

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

More metrics changes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 85.4 KB
Line 
1/* $Id: HostImpl.cpp 28036 2010-04-07 09:47:43Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Host
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#define __STDC_LIMIT_MACROS
23#define __STDC_CONSTANT_MACROS
24
25#include "HostImpl.h"
26
27#ifdef VBOX_WITH_USB
28# include "HostUSBDeviceImpl.h"
29# include "USBDeviceFilterImpl.h"
30# include "USBProxyService.h"
31#endif // VBOX_WITH_USB
32
33#include "HostNetworkInterfaceImpl.h"
34#include "MachineImpl.h"
35#include "AutoCaller.h"
36#include "Logging.h"
37#include "Performance.h"
38
39#include "MediumImpl.h"
40#include "HostPower.h"
41
42#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
43# include <HostHardwareLinux.h>
44#endif
45
46#ifdef VBOX_WITH_RESOURCE_USAGE_API
47# include "PerformanceImpl.h"
48#endif /* VBOX_WITH_RESOURCE_USAGE_API */
49
50#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
51# include <VBox/WinNetConfig.h>
52#endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
53
54#ifdef RT_OS_LINUX
55# include <sys/ioctl.h>
56# include <errno.h>
57# include <net/if.h>
58# include <net/if_arp.h>
59#endif /* RT_OS_LINUX */
60
61#ifdef RT_OS_SOLARIS
62# include <fcntl.h>
63# include <unistd.h>
64# include <stropts.h>
65# include <errno.h>
66# include <limits.h>
67# include <stdio.h>
68# ifdef VBOX_SOLARIS_NSL_RESOLVED
69# include <libdevinfo.h>
70# endif
71# include <net/if.h>
72# include <sys/socket.h>
73# include <sys/sockio.h>
74# include <net/if_arp.h>
75# include <net/if.h>
76# include <sys/types.h>
77# include <sys/stat.h>
78# include <sys/cdio.h>
79# include <sys/dkio.h>
80# include <sys/mnttab.h>
81# include <sys/mntent.h>
82/* Dynamic loading of libhal on Solaris hosts */
83# ifdef VBOX_USE_LIBHAL
84# include "vbox-libhal.h"
85extern "C" char *getfullrawname(char *);
86# endif
87# include "solaris/DynLoadLibSolaris.h"
88#endif /* RT_OS_SOLARIS */
89
90#ifdef RT_OS_WINDOWS
91# define _WIN32_DCOM
92# include <windows.h>
93# include <shellapi.h>
94# define INITGUID
95# include <guiddef.h>
96# include <devguid.h>
97# include <objbase.h>
98//# include <setupapi.h>
99# include <shlobj.h>
100# include <cfgmgr32.h>
101
102#endif /* RT_OS_WINDOWS */
103
104#ifdef RT_OS_DARWIN
105# include "darwin/iokit.h"
106#endif
107
108#ifdef VBOX_WITH_CROGL
109extern bool is3DAccelerationSupported();
110#endif /* VBOX_WITH_CROGL */
111
112#include <iprt/asm.h>
113#include <iprt/string.h>
114#include <iprt/mp.h>
115#include <iprt/time.h>
116#include <iprt/param.h>
117#include <iprt/env.h>
118#include <iprt/mem.h>
119#include <iprt/system.h>
120#ifdef RT_OS_SOLARIS
121# include <iprt/path.h>
122# include <iprt/ctype.h>
123#endif
124#ifdef VBOX_WITH_HOSTNETIF_API
125#include "netif.h"
126#endif
127
128#include <VBox/usb.h>
129#include <VBox/x86.h>
130#include <VBox/err.h>
131#include <VBox/settings.h>
132#include <VBox/sup.h>
133
134#include <stdio.h>
135
136#include <algorithm>
137
138
139////////////////////////////////////////////////////////////////////////////////
140//
141// Host private data definition
142//
143////////////////////////////////////////////////////////////////////////////////
144
145struct Host::Data
146{
147 Data()
148#ifdef VBOX_WITH_USB
149 : usbListsLock(LOCKCLASS_USBLIST)
150#endif
151 {};
152
153 VirtualBox *pParent;
154
155#ifdef VBOX_WITH_USB
156 WriteLockHandle usbListsLock; // protects the below two lists
157
158 USBDeviceFilterList llChildren; // all USB device filters
159 USBDeviceFilterList llUSBDeviceFilters; // USB device filters in use by the USB proxy service
160
161 /** Pointer to the USBProxyService object. */
162 USBProxyService *pUSBProxyService;
163#endif /* VBOX_WITH_USB */
164
165#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
166 /** Object with information about host drives */
167 VBoxMainDriveInfo hostDrives;
168#endif
169 /* Features that can be queried with GetProcessorFeature */
170 BOOL fVTSupported,
171 fLongModeSupported,
172 fPAESupported,
173 fNestedPagingSupported;
174
175 /* 3D hardware acceleration supported? */
176 BOOL f3DAccelerationSupported;
177
178 HostPowerService *pHostPowerService;
179};
180
181
182////////////////////////////////////////////////////////////////////////////////
183//
184// Constructor / destructor
185//
186////////////////////////////////////////////////////////////////////////////////
187
188HRESULT Host::FinalConstruct()
189{
190 return S_OK;
191}
192
193void Host::FinalRelease()
194{
195 uninit();
196}
197
198/**
199 * Initializes the host object.
200 *
201 * @param aParent VirtualBox parent object.
202 */
203HRESULT Host::init(VirtualBox *aParent)
204{
205 LogFlowThisFunc(("aParent=%p\n", aParent));
206
207 /* Enclose the state transition NotReady->InInit->Ready */
208 AutoInitSpan autoInitSpan(this);
209 AssertReturn(autoInitSpan.isOk(), E_FAIL);
210
211 m = new Data();
212
213 m->pParent = aParent;
214
215#ifdef VBOX_WITH_USB
216 /*
217 * Create and initialize the USB Proxy Service.
218 */
219# if defined (RT_OS_DARWIN)
220 m->pUSBProxyService = new USBProxyServiceDarwin(this);
221# elif defined (RT_OS_LINUX)
222 m->pUSBProxyService = new USBProxyServiceLinux(this);
223# elif defined (RT_OS_OS2)
224 m->pUSBProxyService = new USBProxyServiceOs2 (this);
225# elif defined (RT_OS_SOLARIS)
226 m->pUSBProxyService = new USBProxyServiceSolaris(this);
227# elif defined (RT_OS_WINDOWS)
228 m->pUSBProxyService = new USBProxyServiceWindows(this);
229# elif defined (RT_OS_FREEBSD)
230 m->pUSBProxyService = new USBProxyServiceFreeBSD(this);
231# else
232 m->pUSBProxyService = new USBProxyService(this);
233# endif
234 HRESULT hrc = m->pUSBProxyService->init();
235 AssertComRCReturn(hrc, hrc);
236#endif /* VBOX_WITH_USB */
237
238#ifdef VBOX_WITH_RESOURCE_USAGE_API
239 registerMetrics(aParent->performanceCollector());
240#endif /* VBOX_WITH_RESOURCE_USAGE_API */
241
242#if defined (RT_OS_WINDOWS)
243 m->pHostPowerService = new HostPowerServiceWin(m->pParent);
244#elif defined (RT_OS_DARWIN)
245 m->pHostPowerService = new HostPowerServiceDarwin(m->pParent);
246#else
247 m->pHostPowerService = new HostPowerService(m->pParent);
248#endif
249
250 /* Cache the features reported by GetProcessorFeature. */
251 m->fVTSupported = false;
252 m->fLongModeSupported = false;
253 m->fPAESupported = false;
254 m->fNestedPagingSupported = false;
255
256 if (ASMHasCpuId())
257 {
258 uint32_t u32FeaturesECX;
259 uint32_t u32Dummy;
260 uint32_t u32FeaturesEDX;
261 uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32AMDFeatureEDX, u32AMDFeatureECX;
262
263 ASMCpuId(0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX);
264 ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX);
265 /* Query AMD features. */
266 ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &u32AMDFeatureECX, &u32AMDFeatureEDX);
267
268 m->fLongModeSupported = !!(u32AMDFeatureEDX & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE);
269 m->fPAESupported = !!(u32FeaturesEDX & X86_CPUID_FEATURE_EDX_PAE);
270
271 if ( u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX
272 && u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX
273 && u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX
274 )
275 {
276 if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
277 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
278 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
279 )
280 {
281 int rc = SUPR3QueryVTxSupported();
282 if (RT_SUCCESS(rc))
283 m->fVTSupported = true;
284 }
285 }
286 else
287 if ( u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX
288 && u32VendorECX == X86_CPUID_VENDOR_AMD_ECX
289 && u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX
290 )
291 {
292 if ( (u32AMDFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM)
293 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
294 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
295 )
296 m->fVTSupported = true;
297 }
298 }
299
300#if 0 /* needs testing */
301 if (m->fVTSupported)
302 {
303 uint32_t u32Caps = 0;
304
305 int rc = SUPR3QueryVTCaps(&u32Caps);
306 if (RT_SUCCESS(rc))
307 {
308 if (u32Caps & SUPVTCAPS_NESTED_PAGING)
309 m->fNestedPagingSupported = true;
310 }
311 /* else @todo; report BIOS trouble in some way. */
312 }
313#endif
314
315 /* Test for 3D hardware acceleration support */
316 m->f3DAccelerationSupported = false;
317
318#ifdef VBOX_WITH_CROGL
319 m->f3DAccelerationSupported = is3DAccelerationSupported();
320#endif /* VBOX_WITH_CROGL */
321
322 /* Confirm a successful initialization */
323 autoInitSpan.setSucceeded();
324
325 return S_OK;
326}
327
328/**
329 * Uninitializes the host object and sets the ready flag to FALSE.
330 * Called either from FinalRelease() or by the parent when it gets destroyed.
331 */
332void Host::uninit()
333{
334 LogFlowThisFunc(("\n"));
335
336 /* Enclose the state transition Ready->InUninit->NotReady */
337 AutoUninitSpan autoUninitSpan(this);
338 if (autoUninitSpan.uninitDone())
339 return;
340
341#ifdef VBOX_WITH_RESOURCE_USAGE_API
342 unregisterMetrics (m->pParent->performanceCollector());
343#endif /* VBOX_WITH_RESOURCE_USAGE_API */
344
345#ifdef VBOX_WITH_USB
346 /* wait for USB proxy service to terminate before we uninit all USB
347 * devices */
348 LogFlowThisFunc(("Stopping USB proxy service...\n"));
349 delete m->pUSBProxyService;
350 m->pUSBProxyService = NULL;
351 LogFlowThisFunc(("Done stopping USB proxy service.\n"));
352#endif
353
354 delete m->pHostPowerService;
355
356#ifdef VBOX_WITH_USB
357 /* uninit all USB device filters still referenced by clients
358 * Note! HostUSBDeviceFilter::uninit() will modify llChildren. */
359 while (!m->llChildren.empty())
360 {
361 ComObjPtr<HostUSBDeviceFilter> &pChild = m->llChildren.front();
362 pChild->uninit();
363 }
364
365 m->llUSBDeviceFilters.clear();
366#endif
367
368 delete m;
369 m = NULL;
370}
371
372////////////////////////////////////////////////////////////////////////////////
373//
374// ISnapshot public methods
375//
376////////////////////////////////////////////////////////////////////////////////
377
378/**
379 * Returns a list of host DVD drives.
380 *
381 * @returns COM status code
382 * @param drives address of result pointer
383 */
384STDMETHODIMP Host::COMGETTER(DVDDrives)(ComSafeArrayOut(IMedium *, aDrives))
385{
386 CheckComArgOutSafeArrayPointerValid(aDrives);
387
388 AutoCaller autoCaller(this);
389 if (FAILED(autoCaller.rc())) return autoCaller.rc();
390
391 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
392
393 MediaList list;
394 HRESULT rc = getDVDDrives(list);
395 if (SUCCEEDED(rc))
396 {
397 SafeIfaceArray<IMedium> array(list);
398 array.detachTo(ComSafeArrayOutArg(aDrives));
399 }
400
401 return rc;
402}
403
404/**
405 * Returns a list of host floppy drives.
406 *
407 * @returns COM status code
408 * @param drives address of result pointer
409 */
410STDMETHODIMP Host::COMGETTER(FloppyDrives)(ComSafeArrayOut(IMedium *, aDrives))
411{
412 CheckComArgOutPointerValid(aDrives);
413
414 AutoCaller autoCaller(this);
415 if (FAILED(autoCaller.rc())) return autoCaller.rc();
416
417 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
418
419 MediaList list;
420 HRESULT rc = getFloppyDrives(list);
421 if (SUCCEEDED(rc))
422 {
423 SafeIfaceArray<IMedium> collection(list);
424 collection.detachTo(ComSafeArrayOutArg(aDrives));
425 }
426
427 return rc;
428}
429
430
431#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
432# define VBOX_APP_NAME L"VirtualBox"
433
434static int vboxNetWinAddComponent(std::list< ComObjPtr<HostNetworkInterface> > *pPist,
435 INetCfgComponent *pncc)
436{
437 LPWSTR lpszName;
438 GUID IfGuid;
439 HRESULT hr;
440 int rc = VERR_GENERAL_FAILURE;
441
442 hr = pncc->GetDisplayName( &lpszName );
443 Assert(hr == S_OK);
444 if(hr == S_OK)
445 {
446 Bstr name((CBSTR)lpszName);
447
448 hr = pncc->GetInstanceGuid(&IfGuid);
449 Assert(hr == S_OK);
450 if (hr == S_OK)
451 {
452 /* create a new object and add it to the list */
453 ComObjPtr<HostNetworkInterface> iface;
454 iface.createObject();
455 /* remove the curly bracket at the end */
456 if (SUCCEEDED(iface->init (name, Guid (IfGuid), HostNetworkInterfaceType_Bridged)))
457 {
458// iface->setVirtualBox(m->pParent);
459 pPist->push_back(iface);
460 rc = VINF_SUCCESS;
461 }
462 else
463 {
464 Assert(0);
465 }
466 }
467 CoTaskMemFree(lpszName);
468 }
469
470 return rc;
471}
472#endif /* defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
473
474/**
475 * Returns a list of host network interfaces.
476 *
477 * @returns COM status code
478 * @param drives address of result pointer
479 */
480STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInterface*, aNetworkInterfaces))
481{
482#if defined(RT_OS_WINDOWS) || defined(VBOX_WITH_NETFLT) /*|| defined(RT_OS_OS2)*/
483 if (ComSafeArrayOutIsNull(aNetworkInterfaces))
484 return E_POINTER;
485
486 AutoCaller autoCaller(this);
487 if (FAILED(autoCaller.rc())) return autoCaller.rc();
488
489 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
490
491 std::list <ComObjPtr<HostNetworkInterface> > list;
492
493# ifdef VBOX_WITH_HOSTNETIF_API
494 int rc = NetIfList(list);
495 if (rc)
496 {
497 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
498 }
499# else
500
501# if defined(RT_OS_DARWIN)
502 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
503 while (pEtherNICs)
504 {
505 ComObjPtr<HostNetworkInterface> IfObj;
506 IfObj.createObject();
507 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid), HostNetworkInterfaceType_Bridged)))
508 list.push_back(IfObj);
509
510 /* next, free current */
511 void *pvFree = pEtherNICs;
512 pEtherNICs = pEtherNICs->pNext;
513 RTMemFree(pvFree);
514 }
515
516# elif defined(RT_OS_SOLARIS)
517
518# ifdef VBOX_SOLARIS_NSL_RESOLVED
519
520 /*
521 * Use libdevinfo for determining all physical interfaces.
522 */
523 di_node_t Root;
524 Root = di_init("/", DINFOCACHE);
525 if (Root != DI_NODE_NIL)
526 {
527 di_walk_minor(Root, DDI_NT_NET, 0, &list, vboxSolarisAddPhysHostIface);
528 di_fini(Root);
529 }
530
531 /*
532 * Use libdlpi for determining all DLPI interfaces.
533 */
534 if (VBoxSolarisLibDlpiFound())
535 g_pfnLibDlpiWalk(vboxSolarisAddLinkHostIface, &list, 0);
536
537# endif /* VBOX_SOLARIS_NSL_RESOLVED */
538
539 /*
540 * This gets only the list of all plumbed logical interfaces.
541 * This is needed for zones which cannot access the device tree
542 * and in this case we just let them use the list of plumbed interfaces
543 * on the zone.
544 */
545 int Sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
546 if (Sock > 0)
547 {
548 struct lifnum IfNum;
549 memset(&IfNum, 0, sizeof(IfNum));
550 IfNum.lifn_family = AF_INET;
551 int rc = ioctl(Sock, SIOCGLIFNUM, &IfNum);
552 if (!rc)
553 {
554 struct lifreq Ifaces[24];
555 struct lifconf IfConfig;
556 memset(&IfConfig, 0, sizeof(IfConfig));
557 IfConfig.lifc_family = AF_INET;
558 IfConfig.lifc_len = sizeof(Ifaces);
559 IfConfig.lifc_buf = (caddr_t)&(Ifaces[0]);
560 rc = ioctl(Sock, SIOCGLIFCONF, &IfConfig);
561 if (!rc)
562 {
563 for (int i = 0; i < IfNum.lifn_count; i++)
564 {
565 /*
566 * Skip loopback interfaces.
567 */
568 if (!strncmp(Ifaces[i].lifr_name, "lo", 2))
569 continue;
570
571#if 0
572 rc = ioctl(Sock, SIOCGLIFADDR, &(Ifaces[i]));
573 if (!rc)
574 {
575 RTMAC Mac;
576 struct arpreq ArpReq;
577 memcpy(&ArpReq.arp_pa, &Ifaces[i].lifr_addr, sizeof(struct sockaddr_in));
578
579 /*
580 * We might fail if the interface has not been assigned an IP address.
581 * That doesn't matter; as long as it's plumbed we can pick it up.
582 * But, if it has not acquired an IP address we cannot obtain it's MAC
583 * address this way, so we just use all zeros there.
584 */
585 rc = ioctl(Sock, SIOCGARP, &ArpReq);
586 if (!rc)
587 memcpy(&Mac, ArpReq.arp_ha.sa_data, sizeof(RTMAC));
588 else
589 memset(&Mac, 0, sizeof(Mac));
590
591 char szNICDesc[LIFNAMSIZ + 256];
592 char *pszIface = Ifaces[i].lifr_name;
593 strcpy(szNICDesc, pszIface);
594
595 vboxSolarisAddLinkHostIface(pszIface, &list);
596 }
597#endif
598
599 char *pszIface = Ifaces[i].lifr_name;
600 vboxSolarisAddLinkHostIface(pszIface, &list);
601 }
602 }
603 }
604 close(Sock);
605 }
606
607 /*
608 * Weed out duplicates caused by dlpi_walk inconsistencies across Nevadas.
609 */
610 list.sort(vboxSolarisSortNICList);
611 list.unique(vboxSolarisSameNIC);
612
613# elif defined RT_OS_WINDOWS
614# ifndef VBOX_WITH_NETFLT
615 hr = E_NOTIMPL;
616# else /* # if defined VBOX_WITH_NETFLT */
617 INetCfg *pNc;
618 INetCfgComponent *pMpNcc;
619 INetCfgComponent *pTcpIpNcc;
620 LPWSTR lpszApp;
621 HRESULT hr;
622 IEnumNetCfgBindingPath *pEnumBp;
623 INetCfgBindingPath *pBp;
624 IEnumNetCfgBindingInterface *pEnumBi;
625 INetCfgBindingInterface *pBi;
626
627 /* we are using the INetCfg API for getting the list of miniports */
628 hr = VBoxNetCfgWinQueryINetCfg( FALSE,
629 VBOX_APP_NAME,
630 &pNc,
631 &lpszApp );
632 Assert(hr == S_OK);
633 if(hr == S_OK)
634 {
635# ifdef VBOX_NETFLT_ONDEMAND_BIND
636 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
637 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
638# else
639 /* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
640 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
641# ifndef VBOX_WITH_HARDENING
642 if(hr != S_OK)
643 {
644 /* TODO: try to install the netflt from here */
645 }
646# endif
647
648# endif
649
650 if(hr == S_OK)
651 {
652 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
653 Assert(hr == S_OK);
654 if ( hr == S_OK )
655 {
656 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
657 Assert(hr == S_OK || hr == S_FALSE);
658 while( hr == S_OK )
659 {
660 /* S_OK == enabled, S_FALSE == disabled */
661 if(pBp->IsEnabled() == S_OK)
662 {
663 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
664 Assert(hr == S_OK);
665 if ( hr == S_OK )
666 {
667 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
668 Assert(hr == S_OK);
669 while(hr == S_OK)
670 {
671 hr = pBi->GetLowerComponent( &pMpNcc );
672 Assert(hr == S_OK);
673 if(hr == S_OK)
674 {
675 ULONG uComponentStatus;
676 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
677 Assert(hr == S_OK);
678 if(hr == S_OK)
679 {
680 if(uComponentStatus == 0)
681 {
682 vboxNetWinAddComponent(&list, pMpNcc);
683 }
684 }
685 VBoxNetCfgWinReleaseRef( pMpNcc );
686 }
687 VBoxNetCfgWinReleaseRef(pBi);
688
689 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
690 }
691 VBoxNetCfgWinReleaseRef(pEnumBi);
692 }
693 }
694 VBoxNetCfgWinReleaseRef(pBp);
695
696 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
697 }
698 VBoxNetCfgWinReleaseRef(pEnumBp);
699 }
700 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
701 }
702 else
703 {
704 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr));
705 }
706
707 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
708 }
709# endif /* # if defined VBOX_WITH_NETFLT */
710
711
712# elif defined RT_OS_LINUX
713 int sock = socket(AF_INET, SOCK_DGRAM, 0);
714 if (sock >= 0)
715 {
716 char pBuffer[2048];
717 struct ifconf ifConf;
718 ifConf.ifc_len = sizeof(pBuffer);
719 ifConf.ifc_buf = pBuffer;
720 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
721 {
722 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
723 {
724 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
725 {
726 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
727 {
728 RTUUID uuid;
729 Assert(sizeof(uuid) <= sizeof(*pReq));
730 memcpy(&uuid, pReq, sizeof(uuid));
731
732 ComObjPtr<HostNetworkInterface> IfObj;
733 IfObj.createObject();
734 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid), HostNetworkInterfaceType_Bridged)))
735 list.push_back(IfObj);
736 }
737 }
738 }
739 }
740 close(sock);
741 }
742# endif /* RT_OS_LINUX */
743# endif
744
745 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
746 for (it = list.begin(); it != list.end(); ++it)
747 {
748 (*it)->setVirtualBox(m->pParent);
749 }
750
751 SafeIfaceArray<IHostNetworkInterface> networkInterfaces (list);
752 networkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
753
754 return S_OK;
755
756#else
757 /* Not implemented / supported on this platform. */
758 ReturnComNotImplemented();
759#endif
760}
761
762STDMETHODIMP Host::COMGETTER(USBDevices)(ComSafeArrayOut(IHostUSBDevice*, aUSBDevices))
763{
764#ifdef VBOX_WITH_USB
765 CheckComArgOutSafeArrayPointerValid(aUSBDevices);
766
767 AutoCaller autoCaller(this);
768 if (FAILED(autoCaller.rc())) return autoCaller.rc();
769
770 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
771
772 MultiResult rc = checkUSBProxyService();
773 if (FAILED(rc)) return rc;
774
775 return m->pUSBProxyService->getDeviceCollection(ComSafeArrayOutArg(aUSBDevices));
776
777#else
778 /* Note: The GUI depends on this method returning E_NOTIMPL with no
779 * extended error info to indicate that USB is simply not available
780 * (w/o treating it as a failure), for example, as in OSE. */
781 NOREF(aUSBDevices);
782# ifndef RT_OS_WINDOWS
783 NOREF(aUSBDevicesSize);
784# endif
785 ReturnComNotImplemented();
786#endif
787}
788
789STDMETHODIMP Host::COMGETTER(USBDeviceFilters)(ComSafeArrayOut(IHostUSBDeviceFilter*, aUSBDeviceFilters))
790{
791#ifdef VBOX_WITH_USB
792 CheckComArgOutSafeArrayPointerValid(aUSBDeviceFilters);
793
794 AutoCaller autoCaller(this);
795 if (FAILED(autoCaller.rc())) return autoCaller.rc();
796
797 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
798
799 MultiResult rc = checkUSBProxyService();
800 if (FAILED(rc)) return rc;
801
802 SafeIfaceArray<IHostUSBDeviceFilter> collection(m->llUSBDeviceFilters);
803 collection.detachTo(ComSafeArrayOutArg(aUSBDeviceFilters));
804
805 return rc;
806#else
807 /* Note: The GUI depends on this method returning E_NOTIMPL with no
808 * extended error info to indicate that USB is simply not available
809 * (w/o treating it as a failure), for example, as in OSE. */
810 NOREF(aUSBDeviceFilters);
811# ifndef RT_OS_WINDOWS
812 NOREF(aUSBDeviceFiltersSize);
813# endif
814 ReturnComNotImplemented();
815#endif
816}
817
818/**
819 * Returns the number of installed logical processors
820 *
821 * @returns COM status code
822 * @param count address of result variable
823 */
824STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *aCount)
825{
826 CheckComArgOutPointerValid(aCount);
827 // no locking required
828
829 *aCount = RTMpGetPresentCount();
830 return S_OK;
831}
832
833/**
834 * Returns the number of online logical processors
835 *
836 * @returns COM status code
837 * @param count address of result variable
838 */
839STDMETHODIMP Host::COMGETTER(ProcessorOnlineCount)(ULONG *aCount)
840{
841 CheckComArgOutPointerValid(aCount);
842 // no locking required
843
844 *aCount = RTMpGetOnlineCount();
845 return S_OK;
846}
847
848/**
849 * Returns the (approximate) maximum speed of the given host CPU in MHz
850 *
851 * @returns COM status code
852 * @param cpu id to get info for.
853 * @param speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
854 */
855STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *aSpeed)
856{
857 CheckComArgOutPointerValid(aSpeed);
858 // no locking required
859
860 *aSpeed = RTMpGetMaxFrequency(aCpuId);
861 return S_OK;
862}
863
864/**
865 * Returns a description string for the host CPU
866 *
867 * @returns COM status code
868 * @param cpu id to get info for.
869 * @param description address of result variable, empty string if not known or aCpuId is invalid.
870 */
871STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription)
872{
873 CheckComArgOutPointerValid(aDescription);
874 // no locking required
875
876 char szCPUModel[80];
877 int vrc = RTMpGetDescription(aCpuId, szCPUModel, sizeof(szCPUModel));
878 if (RT_FAILURE(vrc))
879 return E_FAIL; /** @todo error reporting? */
880 Bstr (szCPUModel).cloneTo(aDescription);
881 return S_OK;
882}
883
884/**
885 * Returns whether a host processor feature is supported or not
886 *
887 * @returns COM status code
888 * @param Feature to query.
889 * @param address of supported bool result variable
890 */
891STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
892{
893 CheckComArgOutPointerValid(aSupported);
894 AutoCaller autoCaller(this);
895 if (FAILED(autoCaller.rc())) return autoCaller.rc();
896
897 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
898
899 switch (aFeature)
900 {
901 case ProcessorFeature_HWVirtEx:
902 *aSupported = m->fVTSupported;
903 break;
904
905 case ProcessorFeature_PAE:
906 *aSupported = m->fPAESupported;
907 break;
908
909 case ProcessorFeature_LongMode:
910 *aSupported = m->fLongModeSupported;
911 break;
912
913 case ProcessorFeature_NestedPaging:
914 *aSupported = m->fNestedPagingSupported;
915 break;
916
917 default:
918 ReturnComNotImplemented();
919 }
920 return S_OK;
921}
922
923/**
924 * Returns the specific CPUID leaf.
925 *
926 * @returns COM status code
927 * @param aCpuId The CPU number. Mostly ignored.
928 * @param aLeaf The leaf number.
929 * @param aSubLeaf The sub-leaf number.
930 * @param aValEAX Where to return EAX.
931 * @param aValEBX Where to return EBX.
932 * @param aValECX Where to return ECX.
933 * @param aValEDX Where to return EDX.
934 */
935STDMETHODIMP Host::GetProcessorCPUIDLeaf(ULONG aCpuId, ULONG aLeaf, ULONG aSubLeaf,
936 ULONG *aValEAX, ULONG *aValEBX, ULONG *aValECX, ULONG *aValEDX)
937{
938 CheckComArgOutPointerValid(aValEAX);
939 CheckComArgOutPointerValid(aValEBX);
940 CheckComArgOutPointerValid(aValECX);
941 CheckComArgOutPointerValid(aValEDX);
942 // no locking required
943
944 /* Check that the CPU is online. */
945 /** @todo later use RTMpOnSpecific. */
946 if (!RTMpIsCpuOnline(aCpuId))
947 return RTMpIsCpuPresent(aCpuId)
948 ? setError(E_FAIL, tr("CPU no.%u is not present"), aCpuId)
949 : setError(E_FAIL, tr("CPU no.%u is not online"), aCpuId);
950
951 uint32_t uEAX, uEBX, uECX, uEDX;
952 ASMCpuId_Idx_ECX(aLeaf, aSubLeaf, &uEAX, &uEBX, &uECX, &uEDX);
953 *aValEAX = uEAX;
954 *aValEBX = uEBX;
955 *aValECX = uECX;
956 *aValEDX = uEDX;
957
958 return S_OK;
959}
960
961/**
962 * Returns the amount of installed system memory in megabytes
963 *
964 * @returns COM status code
965 * @param size address of result variable
966 */
967STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
968{
969 CheckComArgOutPointerValid(aSize);
970 // no locking required
971
972 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
973 pm::CollectorHAL *hal = pm::createHAL();
974 if (!hal)
975 return E_FAIL;
976 ULONG tmp;
977 int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
978 *aSize /= 1024;
979 delete hal;
980 return rc;
981}
982
983/**
984 * Returns the current system memory free space in megabytes
985 *
986 * @returns COM status code
987 * @param available address of result variable
988 */
989STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
990{
991 CheckComArgOutPointerValid(aAvailable);
992 // no locking required
993
994 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
995 pm::CollectorHAL *hal = pm::createHAL();
996 if (!hal)
997 return E_FAIL;
998 ULONG tmp;
999 int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
1000 *aAvailable /= 1024;
1001 delete hal;
1002 return rc;
1003}
1004
1005/**
1006 * Returns the name string of the host operating system
1007 *
1008 * @returns COM status code
1009 * @param os address of result variable
1010 */
1011STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
1012{
1013 CheckComArgOutPointerValid(aOs);
1014 // no locking required
1015
1016 char szOSName[80];
1017 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
1018 if (RT_FAILURE(vrc))
1019 return E_FAIL; /** @todo error reporting? */
1020 Bstr (szOSName).cloneTo(aOs);
1021 return S_OK;
1022}
1023
1024/**
1025 * Returns the version string of the host operating system
1026 *
1027 * @returns COM status code
1028 * @param os address of result variable
1029 */
1030STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
1031{
1032 CheckComArgOutPointerValid(aVersion);
1033 // no locking required
1034
1035 /* Get the OS release. Reserve some buffer space for the service pack. */
1036 char szOSRelease[128];
1037 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
1038 if (RT_FAILURE(vrc))
1039 return E_FAIL; /** @todo error reporting? */
1040
1041 /* Append the service pack if present. */
1042 char szOSServicePack[80];
1043 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
1044 if (RT_FAILURE(vrc))
1045 {
1046 if (vrc != VERR_NOT_SUPPORTED)
1047 return E_FAIL; /** @todo error reporting? */
1048 szOSServicePack[0] = '\0';
1049 }
1050 if (szOSServicePack[0] != '\0')
1051 {
1052 char *psz = strchr(szOSRelease, '\0');
1053 RTStrPrintf(psz, &szOSRelease[sizeof(szOSRelease)] - psz, "sp%s", szOSServicePack);
1054 }
1055
1056 Bstr(szOSRelease).cloneTo(aVersion);
1057 return S_OK;
1058}
1059
1060/**
1061 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1062 *
1063 * @returns COM status code
1064 * @param time address of result variable
1065 */
1066STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
1067{
1068 CheckComArgOutPointerValid(aUTCTime);
1069 // no locking required
1070
1071 RTTIMESPEC now;
1072 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1073
1074 return S_OK;
1075}
1076
1077STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported)
1078{
1079 CheckComArgOutPointerValid(aSupported);
1080 AutoCaller autoCaller(this);
1081 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1082
1083 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1084
1085 *aSupported = m->f3DAccelerationSupported;
1086
1087 return S_OK;
1088}
1089
1090STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface,
1091 IProgress **aProgress)
1092{
1093 CheckComArgOutPointerValid(aHostNetworkInterface);
1094 CheckComArgOutPointerValid(aProgress);
1095
1096 AutoCaller autoCaller(this);
1097 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1098
1099 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1100
1101 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostNetworkInterface, aProgress);
1102 if (RT_SUCCESS(r))
1103 return S_OK;
1104
1105 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1106}
1107
1108STDMETHODIMP Host::RemoveHostOnlyNetworkInterface(IN_BSTR aId,
1109 IProgress **aProgress)
1110{
1111 CheckComArgOutPointerValid(aProgress);
1112
1113 AutoCaller autoCaller(this);
1114 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1115
1116 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1117
1118 /* first check whether an interface with the given name already exists */
1119 {
1120 ComPtr<IHostNetworkInterface> iface;
1121 if (FAILED(FindHostNetworkInterfaceById(aId,
1122 iface.asOutParam())))
1123 return setError(VBOX_E_OBJECT_NOT_FOUND,
1124 tr("Host network interface with UUID {%RTuuid} does not exist"),
1125 Guid (aId).raw());
1126 }
1127
1128 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, Guid(aId), aProgress);
1129 if (RT_SUCCESS(r))
1130 return S_OK;
1131
1132 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1133}
1134
1135STDMETHODIMP Host::CreateUSBDeviceFilter(IN_BSTR aName,
1136 IHostUSBDeviceFilter **aFilter)
1137{
1138#ifdef VBOX_WITH_USB
1139 CheckComArgStrNotEmptyOrNull(aName);
1140 CheckComArgOutPointerValid(aFilter);
1141
1142 AutoCaller autoCaller(this);
1143 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1144
1145 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1146
1147 ComObjPtr<HostUSBDeviceFilter> filter;
1148 filter.createObject();
1149 HRESULT rc = filter->init(this, aName);
1150 ComAssertComRCRet(rc, rc);
1151 rc = filter.queryInterfaceTo(aFilter);
1152 AssertComRCReturn(rc, rc);
1153 return S_OK;
1154#else
1155 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1156 * extended error info to indicate that USB is simply not available
1157 * (w/o treating it as a failure), for example, as in OSE. */
1158 NOREF(aName);
1159 NOREF(aFilter);
1160 ReturnComNotImplemented();
1161#endif
1162}
1163
1164STDMETHODIMP Host::InsertUSBDeviceFilter(ULONG aPosition,
1165 IHostUSBDeviceFilter *aFilter)
1166{
1167#ifdef VBOX_WITH_USB
1168 CheckComArgNotNull(aFilter);
1169
1170 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1171 AutoCaller autoCaller(this);
1172 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1173
1174 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1175
1176 MultiResult rc = checkUSBProxyService();
1177 if (FAILED(rc)) return rc;
1178
1179 ComObjPtr<HostUSBDeviceFilter> pFilter;
1180 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1181 it != m->llChildren.end();
1182 ++it)
1183 {
1184 if (*it == aFilter)
1185 {
1186 pFilter = *it;
1187 break;
1188 }
1189 }
1190 if (pFilter.isNull())
1191 return setError(VBOX_E_INVALID_OBJECT_STATE,
1192 tr("The given USB device filter is not created within this VirtualBox instance"));
1193
1194 if (pFilter->mInList)
1195 return setError(E_INVALIDARG,
1196 tr("The given USB device filter is already in the list"));
1197
1198 /* iterate to the position... */
1199 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1200 std::advance(itPos, aPosition);
1201 /* ...and insert */
1202 m->llUSBDeviceFilters.insert(itPos, pFilter);
1203 pFilter->mInList = true;
1204
1205 /* notify the proxy (only when the filter is active) */
1206 if ( m->pUSBProxyService->isActive()
1207 && pFilter->getData().mActive)
1208 {
1209 ComAssertRet(pFilter->getId() == NULL, E_FAIL);
1210 pFilter->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1211 }
1212
1213 /* save the global settings */
1214 alock.release();
1215 return rc = m->pParent->saveSettings();
1216#else
1217 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1218 * extended error info to indicate that USB is simply not available
1219 * (w/o treating it as a failure), for example, as in OSE. */
1220 NOREF(aPosition);
1221 NOREF(aFilter);
1222 ReturnComNotImplemented();
1223#endif
1224}
1225
1226STDMETHODIMP Host::RemoveUSBDeviceFilter(ULONG aPosition)
1227{
1228#ifdef VBOX_WITH_USB
1229
1230 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1231 AutoCaller autoCaller(this);
1232 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1233
1234 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1235
1236 MultiResult rc = checkUSBProxyService();
1237 if (FAILED(rc)) return rc;
1238
1239 if (!m->llUSBDeviceFilters.size())
1240 return setError(E_INVALIDARG,
1241 tr("The USB device filter list is empty"));
1242
1243 if (aPosition >= m->llUSBDeviceFilters.size())
1244 return setError(E_INVALIDARG,
1245 tr("Invalid position: %lu (must be in range [0, %lu])"),
1246 aPosition, m->llUSBDeviceFilters.size() - 1);
1247
1248 ComObjPtr<HostUSBDeviceFilter> filter;
1249 {
1250 /* iterate to the position... */
1251 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1252 std::advance (it, aPosition);
1253 /* ...get an element from there... */
1254 filter = *it;
1255 /* ...and remove */
1256 filter->mInList = false;
1257 m->llUSBDeviceFilters.erase(it);
1258 }
1259
1260 /* notify the proxy (only when the filter is active) */
1261 if (m->pUSBProxyService->isActive() && filter->getData().mActive)
1262 {
1263 ComAssertRet(filter->getId() != NULL, E_FAIL);
1264 m->pUSBProxyService->removeFilter(filter->getId());
1265 filter->getId() = NULL;
1266 }
1267
1268 /* save the global settings */
1269 alock.release();
1270 return rc = m->pParent->saveSettings();
1271#else
1272 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1273 * extended error info to indicate that USB is simply not available
1274 * (w/o treating it as a failure), for example, as in OSE. */
1275 NOREF(aPosition);
1276 ReturnComNotImplemented();
1277#endif
1278}
1279
1280STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IMedium **aDrive)
1281{
1282 CheckComArgStrNotEmptyOrNull(aName);
1283 CheckComArgOutPointerValid(aDrive);
1284
1285 *aDrive = NULL;
1286
1287 SafeIfaceArray<IMedium> drivevec;
1288 HRESULT rc = COMGETTER(DVDDrives)(ComSafeArrayAsOutParam(drivevec));
1289 if (FAILED(rc)) return rc;
1290
1291 for (size_t i = 0; i < drivevec.size(); ++i)
1292 {
1293 ComPtr<IMedium> drive = drivevec[i];
1294 Bstr name, location;
1295 rc = drive->COMGETTER(Name)(name.asOutParam());
1296 if (FAILED(rc)) return rc;
1297 rc = drive->COMGETTER(Location)(location.asOutParam());
1298 if (FAILED(rc)) return rc;
1299 if (name == aName || location == aName)
1300 return drive.queryInterfaceTo(aDrive);
1301 }
1302
1303 return setError(VBOX_E_OBJECT_NOT_FOUND,
1304 Medium::tr("The host DVD drive named '%ls' could not be found"), aName);
1305}
1306
1307STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IMedium **aDrive)
1308{
1309 CheckComArgStrNotEmptyOrNull(aName);
1310 CheckComArgOutPointerValid(aDrive);
1311
1312 *aDrive = NULL;
1313
1314 SafeIfaceArray<IMedium> drivevec;
1315 HRESULT rc = COMGETTER(FloppyDrives)(ComSafeArrayAsOutParam(drivevec));
1316 if (FAILED(rc)) return rc;
1317
1318 for (size_t i = 0; i < drivevec.size(); ++i)
1319 {
1320 ComPtr<IMedium> drive = drivevec[i];
1321 Bstr name;
1322 rc = drive->COMGETTER(Name)(name.asOutParam());
1323 if (FAILED(rc)) return rc;
1324 if (name == aName)
1325 return drive.queryInterfaceTo(aDrive);
1326 }
1327
1328 return setError(VBOX_E_OBJECT_NOT_FOUND,
1329 Medium::tr("The host floppy drive named '%ls' could not be found"), aName);
1330}
1331
1332STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
1333{
1334#ifndef VBOX_WITH_HOSTNETIF_API
1335 return E_NOTIMPL;
1336#else
1337 if (!name)
1338 return E_INVALIDARG;
1339 if (!networkInterface)
1340 return E_POINTER;
1341
1342 *networkInterface = NULL;
1343 ComObjPtr<HostNetworkInterface> found;
1344 std::list <ComObjPtr<HostNetworkInterface> > list;
1345 int rc = NetIfList(list);
1346 if (RT_FAILURE(rc))
1347 {
1348 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1349 return E_FAIL;
1350 }
1351 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1352 for (it = list.begin(); it != list.end(); ++it)
1353 {
1354 Bstr n;
1355 (*it)->COMGETTER(Name) (n.asOutParam());
1356 if (n == name)
1357 found = *it;
1358 }
1359
1360 if (!found)
1361 return setError(E_INVALIDARG,
1362 HostNetworkInterface::tr("The host network interface with the given name could not be found"));
1363
1364 found->setVirtualBox(m->pParent);
1365
1366 return found.queryInterfaceTo(networkInterface);
1367#endif
1368}
1369
1370STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
1371{
1372#ifndef VBOX_WITH_HOSTNETIF_API
1373 return E_NOTIMPL;
1374#else
1375 if (Guid(id).isEmpty())
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 g;
1393 (*it)->COMGETTER(Id) (g.asOutParam());
1394 if (g == id)
1395 found = *it;
1396 }
1397
1398 if (!found)
1399 return setError(E_INVALIDARG,
1400 HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
1401
1402 found->setVirtualBox(m->pParent);
1403
1404 return found.queryInterfaceTo(networkInterface);
1405#endif
1406}
1407
1408STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type,
1409 ComSafeArrayOut(IHostNetworkInterface *, aNetworkInterfaces))
1410{
1411 std::list <ComObjPtr<HostNetworkInterface> > allList;
1412 int rc = NetIfList(allList);
1413 if(RT_FAILURE(rc))
1414 return E_FAIL;
1415
1416 std::list <ComObjPtr<HostNetworkInterface> > resultList;
1417
1418 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1419 for (it = allList.begin(); it != allList.end(); ++it)
1420 {
1421 HostNetworkInterfaceType_T t;
1422 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1423 if(FAILED(hr))
1424 return hr;
1425
1426 if(t == type)
1427 {
1428 (*it)->setVirtualBox(m->pParent);
1429 resultList.push_back (*it);
1430 }
1431 }
1432
1433 SafeIfaceArray<IHostNetworkInterface> filteredNetworkInterfaces (resultList);
1434 filteredNetworkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
1435
1436 return S_OK;
1437}
1438
1439STDMETHODIMP Host::FindUSBDeviceByAddress(IN_BSTR aAddress,
1440 IHostUSBDevice **aDevice)
1441{
1442#ifdef VBOX_WITH_USB
1443 CheckComArgStrNotEmptyOrNull(aAddress);
1444 CheckComArgOutPointerValid(aDevice);
1445
1446 *aDevice = NULL;
1447
1448 SafeIfaceArray<IHostUSBDevice> devsvec;
1449 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1450 if (FAILED(rc)) return rc;
1451
1452 for (size_t i = 0; i < devsvec.size(); ++i)
1453 {
1454 Bstr address;
1455 rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
1456 if (FAILED(rc)) return rc;
1457 if (address == aAddress)
1458 {
1459 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1460 }
1461 }
1462
1463 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1464 "Could not find a USB device with address '%ls'"),
1465 aAddress);
1466
1467#else /* !VBOX_WITH_USB */
1468 NOREF(aAddress);
1469 NOREF(aDevice);
1470 return E_NOTIMPL;
1471#endif /* !VBOX_WITH_USB */
1472}
1473
1474STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId,
1475 IHostUSBDevice **aDevice)
1476{
1477#ifdef VBOX_WITH_USB
1478 CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
1479 CheckComArgOutPointerValid(aDevice);
1480
1481 *aDevice = NULL;
1482
1483 SafeIfaceArray<IHostUSBDevice> devsvec;
1484 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1485 if (FAILED(rc)) return rc;
1486
1487 for (size_t i = 0; i < devsvec.size(); ++i)
1488 {
1489 Bstr id;
1490 rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
1491 if (FAILED(rc)) return rc;
1492 if (id == aId)
1493 {
1494 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1495 }
1496 }
1497
1498 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1499 "Could not find a USB device with uuid {%RTuuid}"),
1500 Guid (aId).raw());
1501
1502#else /* !VBOX_WITH_USB */
1503 NOREF(aId);
1504 NOREF(aDevice);
1505 return E_NOTIMPL;
1506#endif /* !VBOX_WITH_USB */
1507}
1508
1509// public methods only for internal purposes
1510////////////////////////////////////////////////////////////////////////////////
1511
1512HRESULT Host::loadSettings(const settings::Host &data)
1513{
1514 HRESULT rc = S_OK;
1515#ifdef VBOX_WITH_USB
1516 AutoCaller autoCaller(this);
1517 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1518
1519 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1520
1521
1522 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
1523 it != data.llUSBDeviceFilters.end();
1524 ++it)
1525 {
1526 const settings::USBDeviceFilter &f = *it;
1527 ComObjPtr<HostUSBDeviceFilter> pFilter;
1528 pFilter.createObject();
1529 rc = pFilter->init(this, f);
1530 if (FAILED(rc)) break;
1531
1532 m->llUSBDeviceFilters.push_back(pFilter);
1533 pFilter->mInList = true;
1534
1535 /* notify the proxy (only when the filter is active) */
1536 if (pFilter->getData().mActive)
1537 {
1538 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
1539 flt->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1540 }
1541 }
1542#else
1543 NOREF(data);
1544#endif /* VBOX_WITH_USB */
1545 return rc;
1546}
1547
1548HRESULT Host::saveSettings(settings::Host &data)
1549{
1550#ifdef VBOX_WITH_USB
1551 AutoCaller autoCaller(this);
1552 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1553
1554 AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1555
1556 data.llUSBDeviceFilters.clear();
1557
1558 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
1559 it != m->llUSBDeviceFilters.end();
1560 ++it)
1561 {
1562 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
1563 settings::USBDeviceFilter f;
1564 pFilter->saveSettings(f);
1565 data.llUSBDeviceFilters.push_back(f);
1566 }
1567#else
1568 NOREF(data);
1569#endif /* VBOX_WITH_USB */
1570
1571 return S_OK;
1572}
1573
1574HRESULT Host::getDVDDrives(MediaList &list)
1575{
1576 HRESULT rc = S_OK;
1577
1578 Assert(isWriteLockOnCurrentThread());
1579
1580 try
1581 {
1582#if defined(RT_OS_WINDOWS)
1583 int sz = GetLogicalDriveStrings(0, NULL);
1584 TCHAR *hostDrives = new TCHAR[sz+1];
1585 GetLogicalDriveStrings(sz, hostDrives);
1586 wchar_t driveName[3] = { '?', ':', '\0' };
1587 TCHAR *p = hostDrives;
1588 do
1589 {
1590 if (GetDriveType(p) == DRIVE_CDROM)
1591 {
1592 driveName[0] = *p;
1593 ComObjPtr<Medium> hostDVDDriveObj;
1594 hostDVDDriveObj.createObject();
1595 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
1596 list.push_back(hostDVDDriveObj);
1597 }
1598 p += _tcslen(p) + 1;
1599 }
1600 while (*p);
1601 delete[] hostDrives;
1602
1603#elif defined(RT_OS_SOLARIS)
1604# ifdef VBOX_USE_LIBHAL
1605 if (!getDVDInfoFromHal(list))
1606# endif
1607 // Not all Solaris versions ship with libhal.
1608 // So use a fallback approach similar to Linux.
1609 {
1610 if (RTEnvExistEx(RTENV_DEFAULT, "VBOX_CDROM"))
1611 {
1612 char *cdromEnv = RTEnvDupEx(RTENV_DEFAULT, "VBOX_CDROM");
1613 char *saveStr = NULL;
1614 char *cdromDrive = NULL;
1615 if (cdromEnv)
1616 cdromDrive = strtok_r(cdromEnv, ":", &saveStr);
1617 while (cdromDrive)
1618 {
1619 if (validateDevice(cdromDrive, true))
1620 {
1621 ComObjPtr<Medium> hostDVDDriveObj;
1622 hostDVDDriveObj.createObject();
1623 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cdromDrive));
1624 list.push_back(hostDVDDriveObj);
1625 }
1626 cdromDrive = strtok_r(NULL, ":", &saveStr);
1627 }
1628 RTStrFree(cdromEnv);
1629 }
1630 else
1631 {
1632 // this might work on Solaris version older than Nevada.
1633 if (validateDevice("/cdrom/cdrom0", true))
1634 {
1635 ComObjPtr<Medium> hostDVDDriveObj;
1636 hostDVDDriveObj.createObject();
1637 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr("cdrom/cdrom0"));
1638 list.push_back(hostDVDDriveObj);
1639 }
1640
1641 // check the mounted drives
1642 parseMountTable(MNTTAB, list);
1643 }
1644 }
1645
1646#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
1647 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
1648 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
1649 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
1650 {
1651 ComObjPtr<Medium> hostDVDDriveObj;
1652 Bstr location(it->mDevice);
1653 Bstr description(it->mDescription);
1654 if (SUCCEEDED(rc))
1655 rc = hostDVDDriveObj.createObject();
1656 if (SUCCEEDED(rc))
1657 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
1658 if (SUCCEEDED(rc))
1659 list.push_back(hostDVDDriveObj);
1660 }
1661#elif defined(RT_OS_DARWIN)
1662 PDARWINDVD cur = DarwinGetDVDDrives();
1663 while (cur)
1664 {
1665 ComObjPtr<Medium> hostDVDDriveObj;
1666 hostDVDDriveObj.createObject();
1667 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
1668 list.push_back(hostDVDDriveObj);
1669
1670 /* next */
1671 void *freeMe = cur;
1672 cur = cur->pNext;
1673 RTMemFree(freeMe);
1674 }
1675#else
1676 /* PORTME */
1677#endif
1678 }
1679 catch(std::bad_alloc &)
1680 {
1681 rc = E_OUTOFMEMORY;
1682 }
1683 return rc;
1684}
1685
1686/**
1687 * Internal implementation for COMGETTER(FloppyDrives) which can be called
1688 * from elsewhere. Caller must hold the Host object write lock!
1689 * @param list
1690 * @return
1691 */
1692HRESULT Host::getFloppyDrives(MediaList &list)
1693{
1694 HRESULT rc = S_OK;
1695
1696 Assert(isWriteLockOnCurrentThread());
1697
1698 try
1699 {
1700#ifdef RT_OS_WINDOWS
1701 int sz = GetLogicalDriveStrings(0, NULL);
1702 TCHAR *hostDrives = new TCHAR[sz+1];
1703 GetLogicalDriveStrings(sz, hostDrives);
1704 wchar_t driveName[3] = { '?', ':', '\0' };
1705 TCHAR *p = hostDrives;
1706 do
1707 {
1708 if (GetDriveType(p) == DRIVE_REMOVABLE)
1709 {
1710 driveName[0] = *p;
1711 ComObjPtr<Medium> hostFloppyDriveObj;
1712 hostFloppyDriveObj.createObject();
1713 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
1714 list.push_back(hostFloppyDriveObj);
1715 }
1716 p += _tcslen(p) + 1;
1717 }
1718 while (*p);
1719 delete[] hostDrives;
1720#elif defined(RT_OS_LINUX)
1721 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
1722 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
1723 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
1724 {
1725 ComObjPtr<Medium> hostFloppyDriveObj;
1726 Bstr location(it->mDevice);
1727 Bstr description(it->mDescription);
1728 if (SUCCEEDED(rc))
1729 rc = hostFloppyDriveObj.createObject();
1730 if (SUCCEEDED(rc))
1731 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
1732 if (SUCCEEDED(rc))
1733 list.push_back(hostFloppyDriveObj);
1734 }
1735#else
1736 NOREF(list);
1737 /* PORTME */
1738#endif
1739 }
1740 catch(std::bad_alloc &)
1741 {
1742 rc = E_OUTOFMEMORY;
1743 }
1744
1745 return rc;
1746}
1747
1748#ifdef VBOX_WITH_USB
1749USBProxyService* Host::usbProxyService()
1750{
1751 return m->pUSBProxyService;
1752}
1753
1754HRESULT Host::addChild(HostUSBDeviceFilter *pChild)
1755{
1756 AutoCaller autoCaller(this);
1757 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1758
1759 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1760
1761 m->llChildren.push_back(pChild);
1762
1763 return S_OK;
1764}
1765
1766HRESULT Host::removeChild(HostUSBDeviceFilter *pChild)
1767{
1768 AutoCaller autoCaller(this);
1769 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1770
1771 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1772
1773 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1774 it != m->llChildren.end();
1775 ++it)
1776 {
1777 if (*it == pChild)
1778 {
1779 m->llChildren.erase(it);
1780 break;
1781 }
1782 }
1783
1784 return S_OK;
1785}
1786
1787VirtualBox* Host::parent()
1788{
1789 return m->pParent;
1790}
1791
1792/**
1793 * Called by setter methods of all USB device filters.
1794 */
1795HRESULT Host::onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
1796 BOOL aActiveChanged /* = FALSE */)
1797{
1798 AutoCaller autoCaller(this);
1799 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1800
1801 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1802
1803 if (aFilter->mInList)
1804 {
1805 if (aActiveChanged)
1806 {
1807 // insert/remove the filter from the proxy
1808 if (aFilter->getData().mActive)
1809 {
1810 ComAssertRet(aFilter->getId() == NULL, E_FAIL);
1811 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
1812 }
1813 else
1814 {
1815 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
1816 m->pUSBProxyService->removeFilter(aFilter->getId());
1817 aFilter->getId() = NULL;
1818 }
1819 }
1820 else
1821 {
1822 if (aFilter->getData().mActive)
1823 {
1824 // update the filter in the proxy
1825 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
1826 m->pUSBProxyService->removeFilter(aFilter->getId());
1827 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
1828 }
1829 }
1830
1831 // save the global settings... yeah, on every single filter property change
1832 alock.release();
1833 return m->pParent->saveSettings();
1834 }
1835
1836 return S_OK;
1837}
1838
1839
1840/**
1841 * Interface for obtaining a copy of the USBDeviceFilterList,
1842 * used by the USBProxyService.
1843 *
1844 * @param aGlobalFilters Where to put the global filter list copy.
1845 * @param aMachines Where to put the machine vector.
1846 */
1847void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
1848{
1849 AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1850
1851 *aGlobalFilters = m->llUSBDeviceFilters;
1852}
1853
1854#endif /* VBOX_WITH_USB */
1855
1856// private methods
1857////////////////////////////////////////////////////////////////////////////////
1858
1859#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
1860/* Solaris hosts, loading libhal at runtime */
1861
1862/**
1863 * Helper function to query the hal subsystem for information about DVD drives attached to the
1864 * system.
1865 *
1866 * @returns true if information was successfully obtained, false otherwise
1867 * @retval list drives found will be attached to this list
1868 */
1869bool Host::getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
1870{
1871 bool halSuccess = false;
1872 DBusError dbusError;
1873 if (!gLibHalCheckPresence())
1874 return false;
1875 gDBusErrorInit (&dbusError);
1876 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1877 if (dbusConnection != 0)
1878 {
1879 LibHalContext *halContext = gLibHalCtxNew();
1880 if (halContext != 0)
1881 {
1882 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1883 {
1884 if (gLibHalCtxInit(halContext, &dbusError))
1885 {
1886 int numDevices;
1887 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1888 "storage.drive_type", "cdrom",
1889 &numDevices, &dbusError);
1890 if (halDevices != 0)
1891 {
1892 /* Hal is installed and working, so if no devices are reported, assume
1893 that there are none. */
1894 halSuccess = true;
1895 for (int i = 0; i < numDevices; i++)
1896 {
1897 char *devNode = gLibHalDeviceGetPropertyString(halContext,
1898 halDevices[i], "block.device", &dbusError);
1899#ifdef RT_OS_SOLARIS
1900 /* The CD/DVD ioctls work only for raw device nodes. */
1901 char *tmp = getfullrawname(devNode);
1902 gLibHalFreeString(devNode);
1903 devNode = tmp;
1904#endif
1905
1906 if (devNode != 0)
1907 {
1908// if (validateDevice(devNode, true))
1909// {
1910 Utf8Str description;
1911 char *vendor, *product;
1912 /* We do not check the error here, as this field may
1913 not even exist. */
1914 vendor = gLibHalDeviceGetPropertyString(halContext,
1915 halDevices[i], "info.vendor", 0);
1916 product = gLibHalDeviceGetPropertyString(halContext,
1917 halDevices[i], "info.product", &dbusError);
1918 if ((product != 0 && product[0] != 0))
1919 {
1920 if ((vendor != 0) && (vendor[0] != 0))
1921 {
1922 description = Utf8StrFmt ("%s %s",
1923 vendor, product);
1924 }
1925 else
1926 {
1927 description = product;
1928 }
1929 ComObjPtr<Medium> hostDVDDriveObj;
1930 hostDVDDriveObj.createObject();
1931 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
1932 Bstr(devNode), Bstr(description));
1933 list.push_back (hostDVDDriveObj);
1934 }
1935 else
1936 {
1937 if (product == 0)
1938 {
1939 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
1940 halDevices[i], dbusError.name, dbusError.message));
1941 gDBusErrorFree(&dbusError);
1942 }
1943 ComObjPtr<Medium> hostDVDDriveObj;
1944 hostDVDDriveObj.createObject();
1945 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
1946 Bstr(devNode));
1947 list.push_back (hostDVDDriveObj);
1948 }
1949 if (vendor != 0)
1950 {
1951 gLibHalFreeString(vendor);
1952 }
1953 if (product != 0)
1954 {
1955 gLibHalFreeString(product);
1956 }
1957// }
1958// else
1959// {
1960// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
1961// }
1962#ifndef RT_OS_SOLARIS
1963 gLibHalFreeString(devNode);
1964#else
1965 free(devNode);
1966#endif
1967 }
1968 else
1969 {
1970 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
1971 halDevices[i], dbusError.name, dbusError.message));
1972 gDBusErrorFree(&dbusError);
1973 }
1974 }
1975 gLibHalFreeStringArray(halDevices);
1976 }
1977 else
1978 {
1979 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1980 gDBusErrorFree(&dbusError);
1981 }
1982 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
1983 {
1984 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1985 gDBusErrorFree(&dbusError);
1986 }
1987 }
1988 else
1989 {
1990 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1991 gDBusErrorFree(&dbusError);
1992 }
1993 gLibHalCtxFree(halContext);
1994 }
1995 else
1996 {
1997 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
1998 }
1999 }
2000 else
2001 {
2002 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
2003 }
2004 gDBusConnectionUnref(dbusConnection);
2005 }
2006 else
2007 {
2008 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2009 gDBusErrorFree(&dbusError);
2010 }
2011 return halSuccess;
2012}
2013
2014
2015/**
2016 * Helper function to query the hal subsystem for information about floppy drives attached to the
2017 * system.
2018 *
2019 * @returns true if information was successfully obtained, false otherwise
2020 * @retval list drives found will be attached to this list
2021 */
2022bool Host::getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
2023{
2024 bool halSuccess = false;
2025 DBusError dbusError;
2026 if (!gLibHalCheckPresence())
2027 return false;
2028 gDBusErrorInit (&dbusError);
2029 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2030 if (dbusConnection != 0)
2031 {
2032 LibHalContext *halContext = gLibHalCtxNew();
2033 if (halContext != 0)
2034 {
2035 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2036 {
2037 if (gLibHalCtxInit(halContext, &dbusError))
2038 {
2039 int numDevices;
2040 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2041 "storage.drive_type", "floppy",
2042 &numDevices, &dbusError);
2043 if (halDevices != 0)
2044 {
2045 /* Hal is installed and working, so if no devices are reported, assume
2046 that there are none. */
2047 halSuccess = true;
2048 for (int i = 0; i < numDevices; i++)
2049 {
2050 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2051 halDevices[i], "storage.drive_type", 0);
2052 if (driveType != 0)
2053 {
2054 if (strcmp(driveType, "floppy") != 0)
2055 {
2056 gLibHalFreeString(driveType);
2057 continue;
2058 }
2059 gLibHalFreeString(driveType);
2060 }
2061 else
2062 {
2063 /* An error occurred. The attribute "storage.drive_type"
2064 probably didn't exist. */
2065 continue;
2066 }
2067 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2068 halDevices[i], "block.device", &dbusError);
2069 if (devNode != 0)
2070 {
2071// if (validateDevice(devNode, false))
2072// {
2073 Utf8Str description;
2074 char *vendor, *product;
2075 /* We do not check the error here, as this field may
2076 not even exist. */
2077 vendor = gLibHalDeviceGetPropertyString(halContext,
2078 halDevices[i], "info.vendor", 0);
2079 product = gLibHalDeviceGetPropertyString(halContext,
2080 halDevices[i], "info.product", &dbusError);
2081 if ((product != 0) && (product[0] != 0))
2082 {
2083 if ((vendor != 0) && (vendor[0] != 0))
2084 {
2085 description = Utf8StrFmt ("%s %s",
2086 vendor, product);
2087 }
2088 else
2089 {
2090 description = product;
2091 }
2092 ComObjPtr<Medium> hostFloppyDrive;
2093 hostFloppyDrive.createObject();
2094 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2095 Bstr(devNode), Bstr(description));
2096 list.push_back (hostFloppyDrive);
2097 }
2098 else
2099 {
2100 if (product == 0)
2101 {
2102 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2103 halDevices[i], dbusError.name, dbusError.message));
2104 gDBusErrorFree(&dbusError);
2105 }
2106 ComObjPtr<Medium> hostFloppyDrive;
2107 hostFloppyDrive.createObject();
2108 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2109 Bstr(devNode));
2110 list.push_back (hostFloppyDrive);
2111 }
2112 if (vendor != 0)
2113 {
2114 gLibHalFreeString(vendor);
2115 }
2116 if (product != 0)
2117 {
2118 gLibHalFreeString(product);
2119 }
2120// }
2121// else
2122// {
2123// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2124// }
2125 gLibHalFreeString(devNode);
2126 }
2127 else
2128 {
2129 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2130 halDevices[i], dbusError.name, dbusError.message));
2131 gDBusErrorFree(&dbusError);
2132 }
2133 }
2134 gLibHalFreeStringArray(halDevices);
2135 }
2136 else
2137 {
2138 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2139 gDBusErrorFree(&dbusError);
2140 }
2141 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2142 {
2143 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2144 gDBusErrorFree(&dbusError);
2145 }
2146 }
2147 else
2148 {
2149 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2150 gDBusErrorFree(&dbusError);
2151 }
2152 gLibHalCtxFree(halContext);
2153 }
2154 else
2155 {
2156 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2157 }
2158 }
2159 else
2160 {
2161 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2162 }
2163 gDBusConnectionUnref(dbusConnection);
2164 }
2165 else
2166 {
2167 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2168 gDBusErrorFree(&dbusError);
2169 }
2170 return halSuccess;
2171}
2172#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2173
2174/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
2175#if defined(RT_OS_SOLARIS)
2176
2177/**
2178 * Helper function to parse the given mount file and add found entries
2179 */
2180void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
2181{
2182#ifdef RT_OS_LINUX
2183 FILE *mtab = setmntent(mountTable, "r");
2184 if (mtab)
2185 {
2186 struct mntent *mntent;
2187 char *mnt_type;
2188 char *mnt_dev;
2189 char *tmp;
2190 while ((mntent = getmntent(mtab)))
2191 {
2192 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2193 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2194 strcpy(mnt_type, mntent->mnt_type);
2195 strcpy(mnt_dev, mntent->mnt_fsname);
2196 // supermount fs case
2197 if (strcmp(mnt_type, "supermount") == 0)
2198 {
2199 tmp = strstr(mntent->mnt_opts, "fs=");
2200 if (tmp)
2201 {
2202 free(mnt_type);
2203 mnt_type = strdup(tmp + strlen("fs="));
2204 if (mnt_type)
2205 {
2206 tmp = strchr(mnt_type, ',');
2207 if (tmp)
2208 *tmp = '\0';
2209 }
2210 }
2211 tmp = strstr(mntent->mnt_opts, "dev=");
2212 if (tmp)
2213 {
2214 free(mnt_dev);
2215 mnt_dev = strdup(tmp + strlen("dev="));
2216 if (mnt_dev)
2217 {
2218 tmp = strchr(mnt_dev, ',');
2219 if (tmp)
2220 *tmp = '\0';
2221 }
2222 }
2223 }
2224 // use strstr here to cover things fs types like "udf,iso9660"
2225 if (strstr(mnt_type, "iso9660") == 0)
2226 {
2227 /** @todo check whether we've already got the drive in our list! */
2228 if (validateDevice(mnt_dev, true))
2229 {
2230 ComObjPtr<Medium> hostDVDDriveObj;
2231 hostDVDDriveObj.createObject();
2232 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
2233 list.push_back (hostDVDDriveObj);
2234 }
2235 }
2236 free(mnt_dev);
2237 free(mnt_type);
2238 }
2239 endmntent(mtab);
2240 }
2241#else // RT_OS_SOLARIS
2242 FILE *mntFile = fopen(mountTable, "r");
2243 if (mntFile)
2244 {
2245 struct mnttab mntTab;
2246 while (getmntent(mntFile, &mntTab) == 0)
2247 {
2248 const char *mountName = mntTab.mnt_special;
2249 const char *mountPoint = mntTab.mnt_mountp;
2250 const char *mountFSType = mntTab.mnt_fstype;
2251 if (mountName && mountPoint && mountFSType)
2252 {
2253 // skip devices we are not interested in
2254 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2255 (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 && // skip devfs (i.e. /devices)
2256 strncmp(mountFSType, "dev", 3) != 0 && // skip dev (i.e. /dev)
2257 strncmp(mountFSType, "lofs", 4) != 0))) // skip loop-back file-system (lofs)
2258 {
2259 char *rawDevName = getfullrawname((char *)mountName);
2260 if (validateDevice(rawDevName, true))
2261 {
2262 ComObjPtr<Medium> hostDVDDriveObj;
2263 hostDVDDriveObj.createObject();
2264 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
2265 list.push_back (hostDVDDriveObj);
2266 }
2267 free(rawDevName);
2268 }
2269 }
2270 }
2271
2272 fclose(mntFile);
2273 }
2274#endif
2275}
2276
2277/**
2278 * Helper function to check whether the given device node is a valid drive
2279 */
2280bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2281{
2282 struct stat statInfo;
2283 bool retValue = false;
2284
2285 // sanity check
2286 if (!deviceNode)
2287 {
2288 return false;
2289 }
2290
2291 // first a simple stat() call
2292 if (stat(deviceNode, &statInfo) < 0)
2293 {
2294 return false;
2295 }
2296 else
2297 {
2298 if (isCDROM)
2299 {
2300 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2301 {
2302 int fileHandle;
2303 // now try to open the device
2304 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2305 if (fileHandle >= 0)
2306 {
2307 cdrom_subchnl cdChannelInfo;
2308 cdChannelInfo.cdsc_format = CDROM_MSF;
2309 // this call will finally reveal the whole truth
2310#ifdef RT_OS_LINUX
2311 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2312 (errno == EIO) || (errno == ENOENT) ||
2313 (errno == EINVAL) || (errno == ENOMEDIUM))
2314#else
2315 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2316 (errno == EIO) || (errno == ENOENT) ||
2317 (errno == EINVAL))
2318#endif
2319 {
2320 retValue = true;
2321 }
2322 close(fileHandle);
2323 }
2324 }
2325 } else
2326 {
2327 // floppy case
2328 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2329 {
2330 /// @todo do some more testing, maybe a nice IOCTL!
2331 retValue = true;
2332 }
2333 }
2334 }
2335 return retValue;
2336}
2337#endif // RT_OS_SOLARIS
2338
2339#ifdef VBOX_WITH_USB
2340/**
2341 * Checks for the presense and status of the USB Proxy Service.
2342 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2343 * warning) if the proxy service is not available due to the way the host is
2344 * configured (at present, that means that usbfs and hal/DBus are not
2345 * available on a Linux host) or E_FAIL and a corresponding error message
2346 * otherwise. Intended to be used by methods that rely on the Proxy Service
2347 * availability.
2348 *
2349 * @note This method may return a warning result code. It is recommended to use
2350 * MultiError to store the return value.
2351 *
2352 * @note Locks this object for reading.
2353 */
2354HRESULT Host::checkUSBProxyService()
2355{
2356 AutoCaller autoCaller(this);
2357 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2358
2359 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2360
2361 AssertReturn(m->pUSBProxyService, E_FAIL);
2362 if (!m->pUSBProxyService->isActive())
2363 {
2364 /* disable the USB controller completely to avoid assertions if the
2365 * USB proxy service could not start. */
2366
2367 if (m->pUSBProxyService->getLastError() == VERR_FILE_NOT_FOUND)
2368 return setWarning (E_FAIL,
2369 tr ("Could not load the Host USB Proxy Service (%Rrc). "
2370 "The service might not be installed on the host computer"),
2371 m->pUSBProxyService->getLastError());
2372 if (m->pUSBProxyService->getLastError() == VINF_SUCCESS)
2373#ifdef RT_OS_LINUX
2374 return setWarning (VBOX_E_HOST_ERROR,
2375# ifdef VBOX_WITH_DBUS
2376 tr ("The USB Proxy Service could not be started, because neither the USB file system (usbfs) nor the hardware information service (hal) is available")
2377# else
2378 tr ("The USB Proxy Service could not be started, because the USB file system (usbfs) is not available")
2379# endif
2380 );
2381#else /* !RT_OS_LINUX */
2382 return setWarning (E_FAIL,
2383 tr ("The USB Proxy Service has not yet been ported to this host"));
2384#endif /* !RT_OS_LINUX */
2385 return setWarning (E_FAIL,
2386 tr ("Could not load the Host USB Proxy service (%Rrc)"),
2387 m->pUSBProxyService->getLastError());
2388 }
2389
2390 return S_OK;
2391}
2392#endif /* VBOX_WITH_USB */
2393
2394#ifdef VBOX_WITH_RESOURCE_USAGE_API
2395void Host::registerMetrics(PerformanceCollector *aCollector)
2396{
2397 pm::CollectorHAL *hal = aCollector->getHAL();
2398 /* Create sub metrics */
2399 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
2400 "Percentage of processor time spent in user mode.");
2401 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
2402 "Percentage of processor time spent in kernel mode.");
2403 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
2404 "Percentage of processor time spent idling.");
2405 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
2406 "Average of current frequency of all processors.");
2407 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
2408 "Total physical memory installed.");
2409 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
2410 "Physical memory currently occupied.");
2411 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
2412 "Physical memory currently available to applications.");
2413 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
2414 "Total physical memory used by the hypervisor.");
2415 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
2416 "Total physical memory free inside the hypervisor.");
2417 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
2418 "Total physical memory ballooned by the hypervisor.");
2419
2420
2421 /* Create and register base metrics */
2422 IUnknown *objptr;
2423 ComObjPtr<Host> tmp = this;
2424 tmp.queryInterfaceTo(&objptr);
2425 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, objptr, cpuLoadUser, cpuLoadKernel,
2426 cpuLoadIdle);
2427 aCollector->registerBaseMetric (cpuLoad);
2428 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, objptr, cpuMhzSM);
2429 aCollector->registerBaseMetric (cpuMhz);
2430 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, objptr, ramUsageTotal, ramUsageUsed,
2431 ramUsageFree, ramVMMUsed, ramVMMFree, ramVMMBallooned);
2432 aCollector->registerBaseMetric (ramUsage);
2433
2434 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
2435 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2436 new pm::AggregateAvg()));
2437 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2438 new pm::AggregateMin()));
2439 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2440 new pm::AggregateMax()));
2441
2442 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
2443 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2444 new pm::AggregateAvg()));
2445 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2446 new pm::AggregateMin()));
2447 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2448 new pm::AggregateMax()));
2449
2450 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
2451 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2452 new pm::AggregateAvg()));
2453 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2454 new pm::AggregateMin()));
2455 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2456 new pm::AggregateMax()));
2457
2458 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
2459 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2460 new pm::AggregateAvg()));
2461 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2462 new pm::AggregateMin()));
2463 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2464 new pm::AggregateMax()));
2465
2466 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
2467 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2468 new pm::AggregateAvg()));
2469 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2470 new pm::AggregateMin()));
2471 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2472 new pm::AggregateMax()));
2473
2474 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
2475 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2476 new pm::AggregateAvg()));
2477 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2478 new pm::AggregateMin()));
2479 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2480 new pm::AggregateMax()));
2481
2482 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
2483 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2484 new pm::AggregateAvg()));
2485 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2486 new pm::AggregateMin()));
2487 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2488 new pm::AggregateMax()));
2489
2490 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMUsed, 0));
2491 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMUsed,
2492 new pm::AggregateAvg()));
2493 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMUsed,
2494 new pm::AggregateMin()));
2495 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMUsed,
2496 new pm::AggregateMax()));
2497
2498 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMFree, 0));
2499 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMFree,
2500 new pm::AggregateAvg()));
2501 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMFree,
2502 new pm::AggregateMin()));
2503 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMFree,
2504 new pm::AggregateMax()));
2505
2506 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMBallooned, 0));
2507 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMBallooned,
2508 new pm::AggregateAvg()));
2509 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMBallooned,
2510 new pm::AggregateMin()));
2511 aCollector->registerMetric(new pm::Metric(ramUsage, ramVMMBallooned,
2512 new pm::AggregateMax()));
2513};
2514
2515void Host::unregisterMetrics (PerformanceCollector *aCollector)
2516{
2517 aCollector->unregisterMetricsFor(this);
2518 aCollector->unregisterBaseMetricsFor(this);
2519};
2520#endif /* VBOX_WITH_RESOURCE_USAGE_API */
2521
2522/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette