VirtualBox

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

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

API: implement IHost::GetProcessorDescription

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