VirtualBox

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

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

ifdef indentation (needs cleanup)

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