VirtualBox

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

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

Main: cleanup: merge VirtualBoxBase{WithTypedChildren}NEXT onto VirtualBoxBase{WithTypedChildren}, adjust Host and Snapshot implementations according to new parents (new locking scheme)

  • 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 21622 2009-07-15 19:04:07Z 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# if defined(RT_OS_DARWIN)
579 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
580 while (pEtherNICs)
581 {
582 ComObjPtr<HostNetworkInterface> IfObj;
583 IfObj.createObject();
584 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid), HostNetworkInterfaceType_Bridged)))
585 list.push_back(IfObj);
586
587 /* next, free current */
588 void *pvFree = pEtherNICs;
589 pEtherNICs = pEtherNICs->pNext;
590 RTMemFree(pvFree);
591 }
592
593# elif defined(RT_OS_SOLARIS)
594
595# ifdef VBOX_SOLARIS_NSL_RESOLVED
596
597 /*
598 * Use libdevinfo for determining all physical interfaces.
599 */
600 di_node_t Root;
601 Root = di_init("/", DINFOCACHE);
602 if (Root != DI_NODE_NIL)
603 {
604 di_walk_minor(Root, DDI_NT_NET, 0, &list, vboxSolarisAddPhysHostIface);
605 di_fini(Root);
606 }
607
608 /*
609 * Use libdlpi for determining all DLPI interfaces.
610 */
611 if (VBoxSolarisLibDlpiFound())
612 g_pfnLibDlpiWalk(vboxSolarisAddLinkHostIface, &list, 0);
613
614# endif /* VBOX_SOLARIS_NSL_RESOLVED */
615
616 /*
617 * This gets only the list of all plumbed logical interfaces.
618 * This is needed for zones which cannot access the device tree
619 * and in this case we just let them use the list of plumbed interfaces
620 * on the zone.
621 */
622 int Sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
623 if (Sock > 0)
624 {
625 struct lifnum IfNum;
626 memset(&IfNum, 0, sizeof(IfNum));
627 IfNum.lifn_family = AF_INET;
628 int rc = ioctl(Sock, SIOCGLIFNUM, &IfNum);
629 if (!rc)
630 {
631 struct lifreq Ifaces[24];
632 struct lifconf IfConfig;
633 memset(&IfConfig, 0, sizeof(IfConfig));
634 IfConfig.lifc_family = AF_INET;
635 IfConfig.lifc_len = sizeof(Ifaces);
636 IfConfig.lifc_buf = (caddr_t)&(Ifaces[0]);
637 rc = ioctl(Sock, SIOCGLIFCONF, &IfConfig);
638 if (!rc)
639 {
640 for (int i = 0; i < IfNum.lifn_count; i++)
641 {
642 /*
643 * Skip loopback interfaces.
644 */
645 if (!strncmp(Ifaces[i].lifr_name, "lo", 2))
646 continue;
647
648#if 0
649 rc = ioctl(Sock, SIOCGLIFADDR, &(Ifaces[i]));
650 if (!rc)
651 {
652 RTMAC Mac;
653 struct arpreq ArpReq;
654 memcpy(&ArpReq.arp_pa, &Ifaces[i].lifr_addr, sizeof(struct sockaddr_in));
655
656 /*
657 * We might fail if the interface has not been assigned an IP address.
658 * That doesn't matter; as long as it's plumbed we can pick it up.
659 * But, if it has not acquired an IP address we cannot obtain it's MAC
660 * address this way, so we just use all zeros there.
661 */
662 rc = ioctl(Sock, SIOCGARP, &ArpReq);
663 if (!rc)
664 memcpy(&Mac, ArpReq.arp_ha.sa_data, sizeof(RTMAC));
665 else
666 memset(&Mac, 0, sizeof(Mac));
667
668 char szNICDesc[LIFNAMSIZ + 256];
669 char *pszIface = Ifaces[i].lifr_name;
670 strcpy(szNICDesc, pszIface);
671
672 vboxSolarisAddLinkHostIface(pszIface, &list);
673 }
674#endif
675
676 char *pszIface = Ifaces[i].lifr_name;
677 vboxSolarisAddLinkHostIface(pszIface, &list);
678 }
679 }
680 }
681 close(Sock);
682 }
683
684 /*
685 * Weed out duplicates caused by dlpi_walk inconsistencies across Nevadas.
686 */
687 list.sort(vboxSolarisSortNICList);
688 list.unique(vboxSolarisSameNIC);
689
690# elif defined RT_OS_WINDOWS
691# ifndef VBOX_WITH_NETFLT
692 hr = E_NOTIMPL;
693# else /* # if defined VBOX_WITH_NETFLT */
694 INetCfg *pNc;
695 INetCfgComponent *pMpNcc;
696 INetCfgComponent *pTcpIpNcc;
697 LPWSTR lpszApp;
698 HRESULT hr;
699 IEnumNetCfgBindingPath *pEnumBp;
700 INetCfgBindingPath *pBp;
701 IEnumNetCfgBindingInterface *pEnumBi;
702 INetCfgBindingInterface *pBi;
703
704 /* we are using the INetCfg API for getting the list of miniports */
705 hr = VBoxNetCfgWinQueryINetCfg( FALSE,
706 VBOX_APP_NAME,
707 &pNc,
708 &lpszApp );
709 Assert(hr == S_OK);
710 if(hr == S_OK)
711 {
712#ifdef VBOX_NETFLT_ONDEMAND_BIND
713 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
714 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
715#else
716 /* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
717 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
718# ifndef VBOX_WITH_HARDENING
719 if(hr != S_OK)
720 {
721 /* TODO: try to install the netflt from here */
722 }
723# endif
724
725#endif
726
727 if(hr == S_OK)
728 {
729 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
730 Assert(hr == S_OK);
731 if ( hr == S_OK )
732 {
733 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
734 Assert(hr == S_OK || hr == S_FALSE);
735 while( hr == S_OK )
736 {
737 /* S_OK == enabled, S_FALSE == disabled */
738 if(pBp->IsEnabled() == S_OK)
739 {
740 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
741 Assert(hr == S_OK);
742 if ( hr == S_OK )
743 {
744 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
745 Assert(hr == S_OK);
746 while(hr == S_OK)
747 {
748 hr = pBi->GetLowerComponent( &pMpNcc );
749 Assert(hr == S_OK);
750 if(hr == S_OK)
751 {
752 ULONG uComponentStatus;
753 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
754 Assert(hr == S_OK);
755 if(hr == S_OK)
756 {
757 if(uComponentStatus == 0)
758 {
759 vboxNetWinAddComponent(&list, pMpNcc);
760 }
761 }
762 VBoxNetCfgWinReleaseRef( pMpNcc );
763 }
764 VBoxNetCfgWinReleaseRef(pBi);
765
766 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
767 }
768 VBoxNetCfgWinReleaseRef(pEnumBi);
769 }
770 }
771 VBoxNetCfgWinReleaseRef(pBp);
772
773 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
774 }
775 VBoxNetCfgWinReleaseRef(pEnumBp);
776 }
777 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
778 }
779 else
780 {
781 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr));
782 }
783
784 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
785 }
786# endif /* # if defined VBOX_WITH_NETFLT */
787
788
789# elif defined RT_OS_LINUX
790 int sock = socket(AF_INET, SOCK_DGRAM, 0);
791 if (sock >= 0)
792 {
793 char pBuffer[2048];
794 struct ifconf ifConf;
795 ifConf.ifc_len = sizeof(pBuffer);
796 ifConf.ifc_buf = pBuffer;
797 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
798 {
799 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
800 {
801 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
802 {
803 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
804 {
805 RTUUID uuid;
806 Assert(sizeof(uuid) <= sizeof(*pReq));
807 memcpy(&uuid, pReq, sizeof(uuid));
808
809 ComObjPtr<HostNetworkInterface> IfObj;
810 IfObj.createObject();
811 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid), HostNetworkInterfaceType_Bridged)))
812 list.push_back(IfObj);
813 }
814 }
815 }
816 }
817 close(sock);
818 }
819# endif /* RT_OS_LINUX */
820#endif
821
822 std::list <ComObjPtr <HostNetworkInterface> >::iterator it;
823 for (it = list.begin(); it != list.end(); ++it)
824 {
825 (*it)->setVirtualBox(mParent);
826 }
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 /** @todo */
966 ReturnComNotImplemented();
967}
968
969/**
970 * Returns whether a host processor feature is supported or not
971 *
972 * @returns COM status code
973 * @param Feature to query.
974 * @param address of supported bool result variable
975 */
976STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
977{
978 CheckComArgOutPointerValid(aSupported);
979 AutoCaller autoCaller (this);
980 CheckComRCReturnRC (autoCaller.rc());
981
982 AutoReadLock alock (this);
983
984 switch (aFeature)
985 {
986 case ProcessorFeature_HWVirtEx:
987 *aSupported = fVTxAMDVSupported;
988 break;
989
990 case ProcessorFeature_PAE:
991 *aSupported = fPAESupported;
992 break;
993
994 case ProcessorFeature_LongMode:
995 *aSupported = fLongModeSupported;
996 break;
997
998 default:
999 ReturnComNotImplemented();
1000 }
1001 return S_OK;
1002}
1003
1004/**
1005 * Returns the amount of installed system memory in megabytes
1006 *
1007 * @returns COM status code
1008 * @param size address of result variable
1009 */
1010STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
1011{
1012 CheckComArgOutPointerValid(aSize);
1013 AutoCaller autoCaller (this);
1014 CheckComRCReturnRC (autoCaller.rc());
1015
1016 AutoWriteLock alock (this);
1017
1018 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1019 pm::CollectorHAL *hal = pm::createHAL();
1020 if (!hal)
1021 return E_FAIL;
1022 ULONG tmp;
1023 int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
1024 *aSize /= 1024;
1025 delete hal;
1026 return rc;
1027}
1028
1029/**
1030 * Returns the current system memory free space in megabytes
1031 *
1032 * @returns COM status code
1033 * @param available address of result variable
1034 */
1035STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
1036{
1037 CheckComArgOutPointerValid(aAvailable);
1038 AutoCaller autoCaller (this);
1039 CheckComRCReturnRC (autoCaller.rc());
1040
1041 AutoWriteLock alock (this);
1042
1043 /* @todo This is an ugly hack. There must be a function in IPRT for that. */
1044 pm::CollectorHAL *hal = pm::createHAL();
1045 if (!hal)
1046 return E_FAIL;
1047 ULONG tmp;
1048 int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
1049 *aAvailable /= 1024;
1050 delete hal;
1051 return rc;
1052}
1053
1054/**
1055 * Returns the name string of the host operating system
1056 *
1057 * @returns COM status code
1058 * @param os address of result variable
1059 */
1060STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
1061{
1062 CheckComArgOutPointerValid(aOs);
1063// AutoCaller autoCaller (this);
1064// CheckComRCReturnRC (autoCaller.rc());
1065
1066// AutoReadLock alock (this);
1067
1068 char szOSName[80];
1069 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
1070 if (RT_FAILURE(vrc))
1071 return E_FAIL; /** @todo error reporting? */
1072 Bstr (szOSName).cloneTo (aOs);
1073 return S_OK;
1074}
1075
1076/**
1077 * Returns the version string of the host operating system
1078 *
1079 * @returns COM status code
1080 * @param os address of result variable
1081 */
1082STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
1083{
1084 CheckComArgOutPointerValid(aVersion);
1085// AutoCaller autoCaller (this);
1086// CheckComRCReturnRC (autoCaller.rc());
1087
1088// AutoReadLock alock (this);
1089
1090 /* Get the OS release. Reserve some buffer space for the service pack. */
1091 char szOSRelease[128];
1092 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
1093 if (RT_FAILURE(vrc))
1094 return E_FAIL; /** @todo error reporting? */
1095
1096 /* Append the service pack if present. */
1097 char szOSServicePack[80];
1098 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
1099 if (RT_FAILURE(vrc))
1100 {
1101 if (vrc != VERR_NOT_SUPPORTED)
1102 return E_FAIL; /** @todo error reporting? */
1103 szOSServicePack[0] = '\0';
1104 }
1105 if (szOSServicePack[0] != '\0')
1106 {
1107 char *psz = strchr(szOSRelease, '\0');
1108 RTStrPrintf(psz, &szOSRelease[sizeof(szOSRelease)] - psz, "sp%s", szOSServicePack);
1109 }
1110
1111 Bstr (szOSRelease).cloneTo (aVersion);
1112 return S_OK;
1113}
1114
1115/**
1116 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1117 *
1118 * @returns COM status code
1119 * @param time address of result variable
1120 */
1121STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
1122{
1123 CheckComArgOutPointerValid(aUTCTime);
1124// AutoCaller autoCaller (this);
1125// CheckComRCReturnRC (autoCaller.rc());
1126
1127// AutoReadLock alock (this);
1128
1129 RTTIMESPEC now;
1130 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1131
1132 return S_OK;
1133}
1134
1135STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported)
1136{
1137 CheckComArgOutPointerValid(aSupported);
1138 AutoCaller autoCaller (this);
1139 CheckComRCReturnRC (autoCaller.rc());
1140
1141 AutoReadLock alock (this);
1142
1143 *aSupported = f3DAccelerationSupported;
1144
1145 return S_OK;
1146}
1147
1148// IHost methods
1149////////////////////////////////////////////////////////////////////////////////
1150STDMETHODIMP
1151Host::CreateHostOnlyNetworkInterface (IHostNetworkInterface **aHostNetworkInterface,
1152 IProgress **aProgress)
1153{
1154 CheckComArgOutPointerValid(aHostNetworkInterface);
1155 CheckComArgOutPointerValid(aProgress);
1156
1157 AutoCaller autoCaller (this);
1158 CheckComRCReturnRC (autoCaller.rc());
1159
1160 AutoWriteLock alock (this);
1161
1162 int r = NetIfCreateHostOnlyNetworkInterface (mParent, aHostNetworkInterface, aProgress);
1163 if(RT_SUCCESS(r))
1164 {
1165 return S_OK;
1166 }
1167
1168 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1169}
1170
1171STDMETHODIMP
1172Host::RemoveHostOnlyNetworkInterface (IN_BSTR aId,
1173 IHostNetworkInterface **aHostNetworkInterface,
1174 IProgress **aProgress)
1175{
1176 CheckComArgOutPointerValid(aHostNetworkInterface);
1177 CheckComArgOutPointerValid(aProgress);
1178
1179 AutoCaller autoCaller (this);
1180 CheckComRCReturnRC (autoCaller.rc());
1181
1182 AutoWriteLock alock (this);
1183
1184 /* first check whether an interface with the given name already exists */
1185 {
1186 ComPtr <IHostNetworkInterface> iface;
1187 if (FAILED (FindHostNetworkInterfaceById (aId, iface.asOutParam())))
1188 return setError (VBOX_E_OBJECT_NOT_FOUND,
1189 tr ("Host network interface with UUID {%RTuuid} does not exist"),
1190 Guid (aId).raw());
1191 }
1192
1193 int r = NetIfRemoveHostOnlyNetworkInterface (mParent, Guid(aId), aHostNetworkInterface, aProgress);
1194 if(RT_SUCCESS(r))
1195 {
1196 return S_OK;
1197 }
1198
1199 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1200}
1201
1202STDMETHODIMP Host::CreateUSBDeviceFilter (IN_BSTR aName, IHostUSBDeviceFilter **aFilter)
1203{
1204#ifdef VBOX_WITH_USB
1205 CheckComArgStrNotEmptyOrNull(aName);
1206 CheckComArgOutPointerValid(aFilter);
1207
1208 AutoCaller autoCaller (this);
1209 CheckComRCReturnRC (autoCaller.rc());
1210
1211 AutoWriteLock alock (this);
1212
1213 ComObjPtr <HostUSBDeviceFilter> filter;
1214 filter.createObject();
1215 HRESULT rc = filter->init (this, aName);
1216 ComAssertComRCRet (rc, rc);
1217 rc = filter.queryInterfaceTo (aFilter);
1218 AssertComRCReturn (rc, rc);
1219 return S_OK;
1220#else
1221 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1222 * extended error info to indicate that USB is simply not available
1223 * (w/o treating it as a failure), for example, as in OSE. */
1224 NOREF(aName);
1225 NOREF(aFilter);
1226 ReturnComNotImplemented();
1227#endif
1228}
1229
1230STDMETHODIMP Host::InsertUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter *aFilter)
1231{
1232#ifdef VBOX_WITH_USB
1233 CheckComArgNotNull(aFilter);
1234
1235 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1236 AutoCaller autoCaller (this);
1237 CheckComRCReturnRC (autoCaller.rc());
1238
1239 AutoWriteLock alock (this);
1240
1241 MultiResult rc = checkUSBProxyService();
1242 CheckComRCReturnRC (rc);
1243
1244 ComObjPtr <HostUSBDeviceFilter> filter = getDependentChild (aFilter);
1245 if (!filter)
1246 return setError (VBOX_E_INVALID_OBJECT_STATE,
1247 tr ("The given USB device filter is not created within "
1248 "this VirtualBox instance"));
1249
1250 if (filter->mInList)
1251 return setError (E_INVALIDARG,
1252 tr ("The given USB device filter is already in the list"));
1253
1254 /* iterate to the position... */
1255 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
1256 std::advance (it, aPosition);
1257 /* ...and insert */
1258 mUSBDeviceFilters.insert (it, filter);
1259 filter->mInList = true;
1260
1261 /* notify the proxy (only when the filter is active) */
1262 if (mUSBProxyService->isActive() && filter->data().mActive)
1263 {
1264 ComAssertRet (filter->id() == NULL, E_FAIL);
1265 filter->id() = mUSBProxyService->insertFilter (&filter->data().mUSBFilter);
1266 }
1267
1268 /* save the global settings */
1269 alock.unlock();
1270 return rc = mParent->saveSettings();
1271#else
1272 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1273 * extended error info to indicate that USB is simply not available
1274 * (w/o treating it as a failure), for example, as in OSE. */
1275 NOREF(aPosition);
1276 NOREF(aFilter);
1277 ReturnComNotImplemented();
1278#endif
1279}
1280
1281STDMETHODIMP Host::RemoveUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter **aFilter)
1282{
1283#ifdef VBOX_WITH_USB
1284 CheckComArgOutPointerValid(aFilter);
1285
1286 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1287 AutoCaller autoCaller (this);
1288 CheckComRCReturnRC (autoCaller.rc());
1289
1290 AutoWriteLock alock (this);
1291
1292 MultiResult rc = checkUSBProxyService();
1293 CheckComRCReturnRC (rc);
1294
1295 if (!mUSBDeviceFilters.size())
1296 return setError (E_INVALIDARG,
1297 tr ("The USB device filter list is empty"));
1298
1299 if (aPosition >= mUSBDeviceFilters.size())
1300 return setError (E_INVALIDARG,
1301 tr ("Invalid position: %lu (must be in range [0, %lu])"),
1302 aPosition, mUSBDeviceFilters.size() - 1);
1303
1304 ComObjPtr <HostUSBDeviceFilter> filter;
1305 {
1306 /* iterate to the position... */
1307 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
1308 std::advance (it, aPosition);
1309 /* ...get an element from there... */
1310 filter = *it;
1311 /* ...and remove */
1312 filter->mInList = false;
1313 mUSBDeviceFilters.erase (it);
1314 }
1315
1316 filter.queryInterfaceTo (aFilter);
1317
1318 /* notify the proxy (only when the filter is active) */
1319 if (mUSBProxyService->isActive() && filter->data().mActive)
1320 {
1321 ComAssertRet (filter->id() != NULL, E_FAIL);
1322 mUSBProxyService->removeFilter (filter->id());
1323 filter->id() = NULL;
1324 }
1325
1326 /* save the global settings */
1327 alock.unlock();
1328 return rc = mParent->saveSettings();
1329#else
1330 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1331 * extended error info to indicate that USB is simply not available
1332 * (w/o treating it as a failure), for example, as in OSE. */
1333 NOREF(aPosition);
1334 NOREF(aFilter);
1335 ReturnComNotImplemented();
1336#endif
1337}
1338
1339// public methods only for internal purposes
1340////////////////////////////////////////////////////////////////////////////////
1341
1342HRESULT Host::loadSettings (const settings::Key &aGlobal)
1343{
1344 using namespace settings;
1345
1346 AutoCaller autoCaller (this);
1347 CheckComRCReturnRC (autoCaller.rc());
1348
1349 AutoWriteLock alock (this);
1350
1351 AssertReturn (!aGlobal.isNull(), E_FAIL);
1352
1353 HRESULT rc = S_OK;
1354
1355#ifdef VBOX_WITH_USB
1356 Key::List filters = aGlobal.key ("USBDeviceFilters").keys ("DeviceFilter");
1357 for (Key::List::const_iterator it = filters.begin();
1358 it != filters.end(); ++ it)
1359 {
1360 Bstr name = (*it).stringValue ("name");
1361 bool active = (*it).value <bool> ("active");
1362
1363 Bstr vendorId = (*it).stringValue ("vendorId");
1364 Bstr productId = (*it).stringValue ("productId");
1365 Bstr revision = (*it).stringValue ("revision");
1366 Bstr manufacturer = (*it).stringValue ("manufacturer");
1367 Bstr product = (*it).stringValue ("product");
1368 Bstr serialNumber = (*it).stringValue ("serialNumber");
1369 Bstr port = (*it).stringValue ("port");
1370
1371 USBDeviceFilterAction_T action;
1372 action = USBDeviceFilterAction_Ignore;
1373 const char *actionStr = (*it).stringValue ("action");
1374 if (strcmp (actionStr, "Ignore") == 0)
1375 action = USBDeviceFilterAction_Ignore;
1376 else
1377 if (strcmp (actionStr, "Hold") == 0)
1378 action = USBDeviceFilterAction_Hold;
1379 else
1380 AssertMsgFailed (("Invalid action: '%s'\n", actionStr));
1381
1382 ComObjPtr <HostUSBDeviceFilter> filterObj;
1383 filterObj.createObject();
1384 rc = filterObj->init (this,
1385 name, active, vendorId, productId, revision,
1386 manufacturer, product, serialNumber, port,
1387 action);
1388 /* error info is set by init() when appropriate */
1389 CheckComRCBreakRC (rc);
1390
1391 mUSBDeviceFilters.push_back (filterObj);
1392 filterObj->mInList = true;
1393
1394 /* notify the proxy (only when the filter is active) */
1395 if (filterObj->data().mActive)
1396 {
1397 HostUSBDeviceFilter *flt = filterObj; /* resolve ambiguity */
1398 flt->id() = mUSBProxyService->insertFilter (&filterObj->data().mUSBFilter);
1399 }
1400 }
1401#endif /* VBOX_WITH_USB */
1402
1403 return rc;
1404}
1405
1406HRESULT Host::saveSettings (settings::Key &aGlobal)
1407{
1408 using namespace settings;
1409
1410 AutoCaller autoCaller (this);
1411 CheckComRCReturnRC (autoCaller.rc());
1412
1413 AutoWriteLock alock (this);
1414
1415 ComAssertRet (!aGlobal.isNull(), E_FAIL);
1416
1417#ifdef VBOX_WITH_USB
1418 /* first, delete the entry */
1419 Key filters = aGlobal.findKey ("USBDeviceFilters");
1420 if (!filters.isNull())
1421 filters.zap();
1422 /* then, recreate it */
1423 filters = aGlobal.createKey ("USBDeviceFilters");
1424
1425 USBDeviceFilterList::const_iterator it = mUSBDeviceFilters.begin();
1426 while (it != mUSBDeviceFilters.end())
1427 {
1428 AutoWriteLock filterLock (*it);
1429 const HostUSBDeviceFilter::Data &data = (*it)->data();
1430
1431 Key filter = filters.appendKey ("DeviceFilter");
1432
1433 filter.setValue <Bstr> ("name", data.mName);
1434 filter.setValue <bool> ("active", !!data.mActive);
1435
1436 /* all are optional */
1437 Bstr str;
1438 (*it)->COMGETTER (VendorId) (str.asOutParam());
1439 if (!str.isNull())
1440 filter.setValue <Bstr> ("vendorId", str);
1441
1442 (*it)->COMGETTER (ProductId) (str.asOutParam());
1443 if (!str.isNull())
1444 filter.setValue <Bstr> ("productId", str);
1445
1446 (*it)->COMGETTER (Revision) (str.asOutParam());
1447 if (!str.isNull())
1448 filter.setValue <Bstr> ("revision", str);
1449
1450 (*it)->COMGETTER (Manufacturer) (str.asOutParam());
1451 if (!str.isNull())
1452 filter.setValue <Bstr> ("manufacturer", str);
1453
1454 (*it)->COMGETTER (Product) (str.asOutParam());
1455 if (!str.isNull())
1456 filter.setValue <Bstr> ("product", str);
1457
1458 (*it)->COMGETTER (SerialNumber) (str.asOutParam());
1459 if (!str.isNull())
1460 filter.setValue <Bstr> ("serialNumber", str);
1461
1462 (*it)->COMGETTER (Port) (str.asOutParam());
1463 if (!str.isNull())
1464 filter.setValue <Bstr> ("port", str);
1465
1466 /* action is mandatory */
1467 USBDeviceFilterAction_T action = USBDeviceFilterAction_Null;
1468 (*it)->COMGETTER (Action) (&action);
1469 if (action == USBDeviceFilterAction_Ignore)
1470 filter.setStringValue ("action", "Ignore");
1471 else if (action == USBDeviceFilterAction_Hold)
1472 filter.setStringValue ("action", "Hold");
1473 else
1474 AssertMsgFailed (("Invalid action: %d\n", action));
1475
1476 ++ it;
1477 }
1478#endif /* VBOX_WITH_USB */
1479
1480 return S_OK;
1481}
1482
1483#ifdef VBOX_WITH_USB
1484/**
1485 * Called by setter methods of all USB device filters.
1486 */
1487HRESULT Host::onUSBDeviceFilterChange (HostUSBDeviceFilter *aFilter,
1488 BOOL aActiveChanged /* = FALSE */)
1489{
1490 AutoCaller autoCaller (this);
1491 CheckComRCReturnRC (autoCaller.rc());
1492
1493 AutoWriteLock alock (this);
1494
1495 if (aFilter->mInList)
1496 {
1497 if (aActiveChanged)
1498 {
1499 // insert/remove the filter from the proxy
1500 if (aFilter->data().mActive)
1501 {
1502 ComAssertRet (aFilter->id() == NULL, E_FAIL);
1503 aFilter->id() = mUSBProxyService->insertFilter (&aFilter->data().mUSBFilter);
1504 }
1505 else
1506 {
1507 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1508 mUSBProxyService->removeFilter (aFilter->id());
1509 aFilter->id() = NULL;
1510 }
1511 }
1512 else
1513 {
1514 if (aFilter->data().mActive)
1515 {
1516 // update the filter in the proxy
1517 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1518 mUSBProxyService->removeFilter (aFilter->id());
1519 aFilter->id() = mUSBProxyService->insertFilter (&aFilter->data().mUSBFilter);
1520 }
1521 }
1522
1523 // save the global settings... yeah, on every single filter property change
1524 alock.unlock();
1525 return mParent->saveSettings();
1526 }
1527
1528 return S_OK;
1529}
1530
1531
1532/**
1533 * Interface for obtaining a copy of the USBDeviceFilterList,
1534 * used by the USBProxyService.
1535 *
1536 * @param aGlobalFilters Where to put the global filter list copy.
1537 * @param aMachines Where to put the machine vector.
1538 */
1539void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters, VirtualBox::SessionMachineVector *aMachines)
1540{
1541 AutoWriteLock alock (this);
1542
1543 mParent->getOpenedMachines (*aMachines);
1544 *aGlobalFilters = mUSBDeviceFilters;
1545}
1546
1547#endif /* VBOX_WITH_USB */
1548
1549// private methods
1550////////////////////////////////////////////////////////////////////////////////
1551
1552#if (defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)) && defined(VBOX_USE_LIBHAL)
1553/* Solaris and FreeBSD hosts, loading libhal at runtime */
1554
1555/**
1556 * Helper function to query the hal subsystem for information about DVD drives attached to the
1557 * system.
1558 *
1559 * @returns true if information was successfully obtained, false otherwise
1560 * @retval list drives found will be attached to this list
1561 */
1562bool Host::getDVDInfoFromHal(std::list <ComObjPtr <HostDVDDrive> > &list)
1563{
1564 bool halSuccess = false;
1565 DBusError dbusError;
1566 if (!gLibHalCheckPresence())
1567 return false;
1568 gDBusErrorInit (&dbusError);
1569 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1570 if (dbusConnection != 0)
1571 {
1572 LibHalContext *halContext = gLibHalCtxNew();
1573 if (halContext != 0)
1574 {
1575 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1576 {
1577 if (gLibHalCtxInit(halContext, &dbusError))
1578 {
1579 int numDevices;
1580 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1581 "storage.drive_type", "cdrom",
1582 &numDevices, &dbusError);
1583 if (halDevices != 0)
1584 {
1585 /* Hal is installed and working, so if no devices are reported, assume
1586 that there are none. */
1587 halSuccess = true;
1588 for (int i = 0; i < numDevices; i++)
1589 {
1590 char *devNode = gLibHalDeviceGetPropertyString(halContext,
1591 halDevices[i], "block.device", &dbusError);
1592#ifdef RT_OS_SOLARIS
1593 /* The CD/DVD ioctls work only for raw device nodes. */
1594 char *tmp = getfullrawname(devNode);
1595 gLibHalFreeString(devNode);
1596 devNode = tmp;
1597#endif
1598
1599#ifdef RT_OS_FREEBSD
1600 /*
1601 * Don't show devices handled by the 'acd' driver.
1602 * The ioctls don't work with it.
1603 */
1604 char *driverName = gLibHalDeviceGetPropertyString(halContext,
1605 halDevices[i], "freebsd.driver", &dbusError);
1606 if (driverName)
1607 {
1608 if (RTStrCmp(driverName, "acd") == 0)
1609 {
1610 gLibHalFreeString(devNode);
1611 devNode = NULL;
1612 }
1613 gLibHalFreeString(driverName);
1614 }
1615#endif
1616
1617 if (devNode != 0)
1618 {
1619// if (validateDevice(devNode, true))
1620// {
1621 Utf8Str description;
1622 char *vendor, *product;
1623 /* We do not check the error here, as this field may
1624 not even exist. */
1625 vendor = gLibHalDeviceGetPropertyString(halContext,
1626 halDevices[i], "info.vendor", 0);
1627 product = gLibHalDeviceGetPropertyString(halContext,
1628 halDevices[i], "info.product", &dbusError);
1629 if ((product != 0 && product[0] != 0))
1630 {
1631 if ((vendor != 0) && (vendor[0] != 0))
1632 {
1633 description = Utf8StrFmt ("%s %s",
1634 vendor, product);
1635 }
1636 else
1637 {
1638 description = product;
1639 }
1640 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1641 hostDVDDriveObj.createObject();
1642 hostDVDDriveObj->init (Bstr (devNode),
1643 Bstr (halDevices[i]),
1644 Bstr (description));
1645 list.push_back (hostDVDDriveObj);
1646 }
1647 else
1648 {
1649 if (product == 0)
1650 {
1651 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
1652 halDevices[i], dbusError.name, dbusError.message));
1653 gDBusErrorFree(&dbusError);
1654 }
1655 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1656 hostDVDDriveObj.createObject();
1657 hostDVDDriveObj->init (Bstr (devNode),
1658 Bstr (halDevices[i]));
1659 list.push_back (hostDVDDriveObj);
1660 }
1661 if (vendor != 0)
1662 {
1663 gLibHalFreeString(vendor);
1664 }
1665 if (product != 0)
1666 {
1667 gLibHalFreeString(product);
1668 }
1669// }
1670// else
1671// {
1672// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
1673// }
1674#ifndef RT_OS_SOLARIS
1675 gLibHalFreeString(devNode);
1676#else
1677 free(devNode);
1678#endif
1679 }
1680 else
1681 {
1682 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
1683 halDevices[i], dbusError.name, dbusError.message));
1684 gDBusErrorFree(&dbusError);
1685 }
1686 }
1687 gLibHalFreeStringArray(halDevices);
1688 }
1689 else
1690 {
1691 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1692 gDBusErrorFree(&dbusError);
1693 }
1694 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
1695 {
1696 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1697 gDBusErrorFree(&dbusError);
1698 }
1699 }
1700 else
1701 {
1702 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1703 gDBusErrorFree(&dbusError);
1704 }
1705 gLibHalCtxFree(halContext);
1706 }
1707 else
1708 {
1709 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
1710 }
1711 }
1712 else
1713 {
1714 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
1715 }
1716 gDBusConnectionUnref(dbusConnection);
1717 }
1718 else
1719 {
1720 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1721 gDBusErrorFree(&dbusError);
1722 }
1723 return halSuccess;
1724}
1725
1726
1727/**
1728 * Helper function to query the hal subsystem for information about floppy drives attached to the
1729 * system.
1730 *
1731 * @returns true if information was successfully obtained, false otherwise
1732 * @retval list drives found will be attached to this list
1733 */
1734bool Host::getFloppyInfoFromHal(std::list <ComObjPtr <HostFloppyDrive> > &list)
1735{
1736 bool halSuccess = false;
1737 DBusError dbusError;
1738 if (!gLibHalCheckPresence())
1739 return false;
1740 gDBusErrorInit (&dbusError);
1741 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
1742 if (dbusConnection != 0)
1743 {
1744 LibHalContext *halContext = gLibHalCtxNew();
1745 if (halContext != 0)
1746 {
1747 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
1748 {
1749 if (gLibHalCtxInit(halContext, &dbusError))
1750 {
1751 int numDevices;
1752 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
1753 "storage.drive_type", "floppy",
1754 &numDevices, &dbusError);
1755 if (halDevices != 0)
1756 {
1757 /* Hal is installed and working, so if no devices are reported, assume
1758 that there are none. */
1759 halSuccess = true;
1760 for (int i = 0; i < numDevices; i++)
1761 {
1762 char *driveType = gLibHalDeviceGetPropertyString(halContext,
1763 halDevices[i], "storage.drive_type", 0);
1764 if (driveType != 0)
1765 {
1766 if (strcmp(driveType, "floppy") != 0)
1767 {
1768 gLibHalFreeString(driveType);
1769 continue;
1770 }
1771 gLibHalFreeString(driveType);
1772 }
1773 else
1774 {
1775 /* An error occurred. The attribute "storage.drive_type"
1776 probably didn't exist. */
1777 continue;
1778 }
1779 char *devNode = gLibHalDeviceGetPropertyString(halContext,
1780 halDevices[i], "block.device", &dbusError);
1781 if (devNode != 0)
1782 {
1783// if (validateDevice(devNode, false))
1784// {
1785 Utf8Str description;
1786 char *vendor, *product;
1787 /* We do not check the error here, as this field may
1788 not even exist. */
1789 vendor = gLibHalDeviceGetPropertyString(halContext,
1790 halDevices[i], "info.vendor", 0);
1791 product = gLibHalDeviceGetPropertyString(halContext,
1792 halDevices[i], "info.product", &dbusError);
1793 if ((product != 0) && (product[0] != 0))
1794 {
1795 if ((vendor != 0) && (vendor[0] != 0))
1796 {
1797 description = Utf8StrFmt ("%s %s",
1798 vendor, product);
1799 }
1800 else
1801 {
1802 description = product;
1803 }
1804 ComObjPtr <HostFloppyDrive> hostFloppyDrive;
1805 hostFloppyDrive.createObject();
1806 hostFloppyDrive->init (Bstr (devNode),
1807 Bstr (halDevices[i]),
1808 Bstr (description));
1809 list.push_back (hostFloppyDrive);
1810 }
1811 else
1812 {
1813 if (product == 0)
1814 {
1815 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
1816 halDevices[i], dbusError.name, dbusError.message));
1817 gDBusErrorFree(&dbusError);
1818 }
1819 ComObjPtr <HostFloppyDrive> hostFloppyDrive;
1820 hostFloppyDrive.createObject();
1821 hostFloppyDrive->init (Bstr (devNode),
1822 Bstr (halDevices[i]));
1823 list.push_back (hostFloppyDrive);
1824 }
1825 if (vendor != 0)
1826 {
1827 gLibHalFreeString(vendor);
1828 }
1829 if (product != 0)
1830 {
1831 gLibHalFreeString(product);
1832 }
1833// }
1834// else
1835// {
1836// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
1837// }
1838 gLibHalFreeString(devNode);
1839 }
1840 else
1841 {
1842 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
1843 halDevices[i], dbusError.name, dbusError.message));
1844 gDBusErrorFree(&dbusError);
1845 }
1846 }
1847 gLibHalFreeStringArray(halDevices);
1848 }
1849 else
1850 {
1851 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1852 gDBusErrorFree(&dbusError);
1853 }
1854 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
1855 {
1856 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1857 gDBusErrorFree(&dbusError);
1858 }
1859 }
1860 else
1861 {
1862 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1863 gDBusErrorFree(&dbusError);
1864 }
1865 gLibHalCtxFree(halContext);
1866 }
1867 else
1868 {
1869 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
1870 }
1871 }
1872 else
1873 {
1874 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
1875 }
1876 gDBusConnectionUnref(dbusConnection);
1877 }
1878 else
1879 {
1880 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
1881 gDBusErrorFree(&dbusError);
1882 }
1883 return halSuccess;
1884}
1885#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
1886
1887#if defined(RT_OS_SOLARIS)
1888
1889/**
1890 * Helper function to parse the given mount file and add found entries
1891 */
1892void Host::parseMountTable(char *mountTable, std::list <ComObjPtr <HostDVDDrive> > &list)
1893{
1894#ifdef RT_OS_LINUX
1895 FILE *mtab = setmntent(mountTable, "r");
1896 if (mtab)
1897 {
1898 struct mntent *mntent;
1899 char *mnt_type;
1900 char *mnt_dev;
1901 char *tmp;
1902 while ((mntent = getmntent(mtab)))
1903 {
1904 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
1905 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
1906 strcpy(mnt_type, mntent->mnt_type);
1907 strcpy(mnt_dev, mntent->mnt_fsname);
1908 // supermount fs case
1909 if (strcmp(mnt_type, "supermount") == 0)
1910 {
1911 tmp = strstr(mntent->mnt_opts, "fs=");
1912 if (tmp)
1913 {
1914 free(mnt_type);
1915 mnt_type = strdup(tmp + strlen("fs="));
1916 if (mnt_type)
1917 {
1918 tmp = strchr(mnt_type, ',');
1919 if (tmp)
1920 *tmp = '\0';
1921 }
1922 }
1923 tmp = strstr(mntent->mnt_opts, "dev=");
1924 if (tmp)
1925 {
1926 free(mnt_dev);
1927 mnt_dev = strdup(tmp + strlen("dev="));
1928 if (mnt_dev)
1929 {
1930 tmp = strchr(mnt_dev, ',');
1931 if (tmp)
1932 *tmp = '\0';
1933 }
1934 }
1935 }
1936 // use strstr here to cover things fs types like "udf,iso9660"
1937 if (strstr(mnt_type, "iso9660") == 0)
1938 {
1939 /** @todo check whether we've already got the drive in our list! */
1940 if (validateDevice(mnt_dev, true))
1941 {
1942 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1943 hostDVDDriveObj.createObject();
1944 hostDVDDriveObj->init (Bstr (mnt_dev));
1945 list.push_back (hostDVDDriveObj);
1946 }
1947 }
1948 free(mnt_dev);
1949 free(mnt_type);
1950 }
1951 endmntent(mtab);
1952 }
1953#else // RT_OS_SOLARIS
1954 FILE *mntFile = fopen(mountTable, "r");
1955 if (mntFile)
1956 {
1957 struct mnttab mntTab;
1958 while (getmntent(mntFile, &mntTab) == 0)
1959 {
1960 char *mountName = strdup(mntTab.mnt_special);
1961 char *mountPoint = strdup(mntTab.mnt_mountp);
1962 char *mountFSType = strdup(mntTab.mnt_fstype);
1963
1964 // skip devices we are not interested in
1965 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
1966 (*mountFSType && (strcmp(mountFSType, "devfs") != 0 && // skip devfs (i.e. /devices)
1967 strcmp(mountFSType, "dev") != 0 && // skip dev (i.e. /dev)
1968 strcmp(mountFSType, "lofs") != 0)) && // skip loop-back file-system (lofs)
1969 (*mountPoint && strcmp(mountPoint, "/") != 0)) // skip point '/' (Can CD/DVD be mounted at '/' ???)
1970 {
1971 char *rawDevName = getfullrawname(mountName);
1972 if (validateDevice(rawDevName, true))
1973 {
1974 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1975 hostDVDDriveObj.createObject();
1976 hostDVDDriveObj->init (Bstr (rawDevName));
1977 list.push_back (hostDVDDriveObj);
1978 }
1979 free(rawDevName);
1980 }
1981
1982 free(mountName);
1983 free(mountPoint);
1984 free(mountFSType);
1985 }
1986
1987 fclose(mntFile);
1988 }
1989#endif
1990}
1991
1992/**
1993 * Helper function to check whether the given device node is a valid drive
1994 */
1995bool Host::validateDevice(const char *deviceNode, bool isCDROM)
1996{
1997 struct stat statInfo;
1998 bool retValue = false;
1999
2000 // sanity check
2001 if (!deviceNode)
2002 {
2003 return false;
2004 }
2005
2006 // first a simple stat() call
2007 if (stat(deviceNode, &statInfo) < 0)
2008 {
2009 return false;
2010 } else
2011 {
2012 if (isCDROM)
2013 {
2014 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2015 {
2016 int fileHandle;
2017 // now try to open the device
2018 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2019 if (fileHandle >= 0)
2020 {
2021 cdrom_subchnl cdChannelInfo;
2022 cdChannelInfo.cdsc_format = CDROM_MSF;
2023 // this call will finally reveal the whole truth
2024#ifdef RT_OS_LINUX
2025 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2026 (errno == EIO) || (errno == ENOENT) ||
2027 (errno == EINVAL) || (errno == ENOMEDIUM))
2028#else
2029 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2030 (errno == EIO) || (errno == ENOENT) ||
2031 (errno == EINVAL))
2032#endif
2033 {
2034 retValue = true;
2035 }
2036 close(fileHandle);
2037 }
2038 }
2039 } else
2040 {
2041 // floppy case
2042 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2043 {
2044 /// @todo do some more testing, maybe a nice IOCTL!
2045 retValue = true;
2046 }
2047 }
2048 }
2049 return retValue;
2050}
2051#endif // RT_OS_SOLARIS
2052
2053#ifdef VBOX_WITH_USB
2054/**
2055 * Checks for the presense and status of the USB Proxy Service.
2056 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2057 * warning) if the proxy service is not available due to the way the host is
2058 * configured (at present, that means that usbfs and hal/DBus are not
2059 * available on a Linux host) or E_FAIL and a corresponding error message
2060 * otherwise. Intended to be used by methods that rely on the Proxy Service
2061 * availability.
2062 *
2063 * @note This method may return a warning result code. It is recommended to use
2064 * MultiError to store the return value.
2065 *
2066 * @note Locks this object for reading.
2067 */
2068HRESULT Host::checkUSBProxyService()
2069{
2070 AutoCaller autoCaller (this);
2071 CheckComRCReturnRC (autoCaller.rc());
2072
2073 AutoWriteLock alock (this);
2074
2075 AssertReturn (mUSBProxyService, E_FAIL);
2076 if (!mUSBProxyService->isActive())
2077 {
2078 /* disable the USB controller completely to avoid assertions if the
2079 * USB proxy service could not start. */
2080
2081 if (mUSBProxyService->getLastError() == VERR_FILE_NOT_FOUND)
2082 return setWarning (E_FAIL,
2083 tr ("Could not load the Host USB Proxy Service (%Rrc). "
2084 "The service might not be installed on the host computer"),
2085 mUSBProxyService->getLastError());
2086 if (mUSBProxyService->getLastError() == VINF_SUCCESS)
2087#ifdef RT_OS_LINUX
2088 return setWarning (VBOX_E_HOST_ERROR,
2089# ifdef VBOX_WITH_DBUS
2090 tr ("The USB Proxy Service could not be started, because neither the USB file system (usbfs) nor the hardware information service (hal) is available")
2091# else
2092 tr ("The USB Proxy Service could not be started, because the USB file system (usbfs) is not available")
2093# endif
2094 );
2095#else /* !RT_OS_LINUX */
2096 return setWarning (E_FAIL,
2097 tr ("The USB Proxy Service has not yet been ported to this host"));
2098#endif /* !RT_OS_LINUX */
2099 return setWarning (E_FAIL,
2100 tr ("Could not load the Host USB Proxy service (%Rrc)"),
2101 mUSBProxyService->getLastError());
2102 }
2103
2104 return S_OK;
2105}
2106#endif /* VBOX_WITH_USB */
2107
2108#ifdef VBOX_WITH_RESOURCE_USAGE_API
2109void Host::registerMetrics (PerformanceCollector *aCollector)
2110{
2111 pm::CollectorHAL *hal = aCollector->getHAL();
2112 /* Create sub metrics */
2113 pm::SubMetric *cpuLoadUser = new pm::SubMetric ("CPU/Load/User",
2114 "Percentage of processor time spent in user mode.");
2115 pm::SubMetric *cpuLoadKernel = new pm::SubMetric ("CPU/Load/Kernel",
2116 "Percentage of processor time spent in kernel mode.");
2117 pm::SubMetric *cpuLoadIdle = new pm::SubMetric ("CPU/Load/Idle",
2118 "Percentage of processor time spent idling.");
2119 pm::SubMetric *cpuMhzSM = new pm::SubMetric ("CPU/MHz",
2120 "Average of current frequency of all processors.");
2121 pm::SubMetric *ramUsageTotal = new pm::SubMetric ("RAM/Usage/Total",
2122 "Total physical memory installed.");
2123 pm::SubMetric *ramUsageUsed = new pm::SubMetric ("RAM/Usage/Used",
2124 "Physical memory currently occupied.");
2125 pm::SubMetric *ramUsageFree = new pm::SubMetric ("RAM/Usage/Free",
2126 "Physical memory currently available to applications.");
2127 /* Create and register base metrics */
2128 IUnknown *objptr;
2129 ComObjPtr <Host> tmp = this;
2130 tmp.queryInterfaceTo (&objptr);
2131 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw (hal, objptr, cpuLoadUser, cpuLoadKernel,
2132 cpuLoadIdle);
2133 aCollector->registerBaseMetric (cpuLoad);
2134 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz (hal, objptr, cpuMhzSM);
2135 aCollector->registerBaseMetric (cpuMhz);
2136 pm::BaseMetric *ramUsage = new pm::HostRamUsage (hal, objptr, ramUsageTotal, ramUsageUsed,
2137 ramUsageFree);
2138 aCollector->registerBaseMetric (ramUsage);
2139
2140 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser, 0));
2141 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
2142 new pm::AggregateAvg()));
2143 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
2144 new pm::AggregateMin()));
2145 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadUser,
2146 new pm::AggregateMax()));
2147
2148 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel, 0));
2149 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
2150 new pm::AggregateAvg()));
2151 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
2152 new pm::AggregateMin()));
2153 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadKernel,
2154 new pm::AggregateMax()));
2155
2156 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle, 0));
2157 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
2158 new pm::AggregateAvg()));
2159 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
2160 new pm::AggregateMin()));
2161 aCollector->registerMetric (new pm::Metric(cpuLoad, cpuLoadIdle,
2162 new pm::AggregateMax()));
2163
2164 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM, 0));
2165 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
2166 new pm::AggregateAvg()));
2167 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
2168 new pm::AggregateMin()));
2169 aCollector->registerMetric (new pm::Metric(cpuMhz, cpuMhzSM,
2170 new pm::AggregateMax()));
2171
2172 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal, 0));
2173 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
2174 new pm::AggregateAvg()));
2175 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
2176 new pm::AggregateMin()));
2177 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageTotal,
2178 new pm::AggregateMax()));
2179
2180 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed, 0));
2181 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
2182 new pm::AggregateAvg()));
2183 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
2184 new pm::AggregateMin()));
2185 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageUsed,
2186 new pm::AggregateMax()));
2187
2188 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree, 0));
2189 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
2190 new pm::AggregateAvg()));
2191 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
2192 new pm::AggregateMin()));
2193 aCollector->registerMetric (new pm::Metric(ramUsage, ramUsageFree,
2194 new pm::AggregateMax()));
2195};
2196
2197void Host::unregisterMetrics (PerformanceCollector *aCollector)
2198{
2199 aCollector->unregisterMetricsFor (this);
2200 aCollector->unregisterBaseMetricsFor (this);
2201};
2202#endif /* VBOX_WITH_RESOURCE_USAGE_API */
2203
2204STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IHostDVDDrive **aDrive)
2205{
2206 CheckComArgNotNull(aName);
2207 CheckComArgOutPointerValid(aDrive);
2208
2209 *aDrive = NULL;
2210
2211 SafeIfaceArray <IHostDVDDrive> drivevec;
2212 HRESULT rc = COMGETTER(DVDDrives) (ComSafeArrayAsOutParam(drivevec));
2213 CheckComRCReturnRC (rc);
2214
2215 for (size_t i = 0; i < drivevec.size(); ++i)
2216 {
2217 Bstr name;
2218 rc = drivevec[i]->COMGETTER(Name) (name.asOutParam());
2219 CheckComRCReturnRC (rc);
2220 if (name == aName)
2221 {
2222 ComObjPtr<HostDVDDrive> found;
2223 found.createObject();
2224 Bstr udi, description;
2225 rc = drivevec[i]->COMGETTER(Udi) (udi.asOutParam());
2226 CheckComRCReturnRC (rc);
2227 rc = drivevec[i]->COMGETTER(Description) (description.asOutParam());
2228 CheckComRCReturnRC (rc);
2229 found->init(name, udi, description);
2230 return found.queryInterfaceTo(aDrive);
2231 }
2232 }
2233
2234 return setError (VBOX_E_OBJECT_NOT_FOUND, HostDVDDrive::tr (
2235 "The host DVD drive named '%ls' could not be found"), aName);
2236}
2237
2238STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IHostFloppyDrive **aDrive)
2239{
2240 CheckComArgNotNull(aName);
2241 CheckComArgOutPointerValid(aDrive);
2242
2243 *aDrive = NULL;
2244
2245 SafeIfaceArray <IHostFloppyDrive> drivevec;
2246 HRESULT rc = COMGETTER(FloppyDrives) (ComSafeArrayAsOutParam(drivevec));
2247 CheckComRCReturnRC (rc);
2248
2249 for (size_t i = 0; i < drivevec.size(); ++i)
2250 {
2251 Bstr name;
2252 rc = drivevec[i]->COMGETTER(Name) (name.asOutParam());
2253 CheckComRCReturnRC (rc);
2254 if (name == aName)
2255 {
2256 ComObjPtr<HostFloppyDrive> found;
2257 found.createObject();
2258 Bstr udi, description;
2259 rc = drivevec[i]->COMGETTER(Udi) (udi.asOutParam());
2260 CheckComRCReturnRC (rc);
2261 rc = drivevec[i]->COMGETTER(Description) (description.asOutParam());
2262 CheckComRCReturnRC (rc);
2263 found->init(name, udi, description);
2264 return found.queryInterfaceTo(aDrive);
2265 }
2266 }
2267
2268 return setError (VBOX_E_OBJECT_NOT_FOUND, HostFloppyDrive::tr (
2269 "The host floppy drive named '%ls' could not be found"), aName);
2270}
2271
2272STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
2273{
2274#ifndef VBOX_WITH_HOSTNETIF_API
2275 return E_NOTIMPL;
2276#else
2277 if (!name)
2278 return E_INVALIDARG;
2279 if (!networkInterface)
2280 return E_POINTER;
2281
2282 *networkInterface = NULL;
2283 ComObjPtr <HostNetworkInterface> found;
2284 std::list <ComObjPtr <HostNetworkInterface> > list;
2285 int rc = NetIfList(list);
2286 if (RT_FAILURE(rc))
2287 {
2288 Log(("Failed to get host network interface list with rc=%Vrc\n", rc));
2289 return E_FAIL;
2290 }
2291 std::list <ComObjPtr <HostNetworkInterface> >::iterator it;
2292 for (it = list.begin(); it != list.end(); ++it)
2293 {
2294 Bstr n;
2295 (*it)->COMGETTER(Name) (n.asOutParam());
2296 if (n == name)
2297 found = *it;
2298 }
2299
2300 if (!found)
2301 return setError (E_INVALIDARG, HostNetworkInterface::tr (
2302 "The host network interface with the given name could not be found"));
2303
2304 found->setVirtualBox(mParent);
2305
2306 return found.queryInterfaceTo (networkInterface);
2307#endif
2308}
2309
2310STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
2311{
2312#ifndef VBOX_WITH_HOSTNETIF_API
2313 return E_NOTIMPL;
2314#else
2315 if (Guid(id).isEmpty())
2316 return E_INVALIDARG;
2317 if (!networkInterface)
2318 return E_POINTER;
2319
2320 *networkInterface = NULL;
2321 ComObjPtr <HostNetworkInterface> found;
2322 std::list <ComObjPtr <HostNetworkInterface> > list;
2323 int rc = NetIfList(list);
2324 if (RT_FAILURE(rc))
2325 {
2326 Log(("Failed to get host network interface list with rc=%Vrc\n", rc));
2327 return E_FAIL;
2328 }
2329 std::list <ComObjPtr <HostNetworkInterface> >::iterator it;
2330 for (it = list.begin(); it != list.end(); ++it)
2331 {
2332 Bstr g;
2333 (*it)->COMGETTER(Id) (g.asOutParam());
2334 if (g == id)
2335 found = *it;
2336 }
2337
2338 if (!found)
2339 return setError (E_INVALIDARG, HostNetworkInterface::tr (
2340 "The host network interface with the given GUID could not be found"));
2341
2342 found->setVirtualBox(mParent);
2343
2344 return found.queryInterfaceTo (networkInterface);
2345#endif
2346}
2347
2348STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type, ComSafeArrayOut (IHostNetworkInterface *, aNetworkInterfaces))
2349{
2350 std::list <ComObjPtr <HostNetworkInterface> > allList;
2351 int rc = NetIfList(allList);
2352 if(RT_FAILURE(rc))
2353 return E_FAIL;
2354
2355 std::list <ComObjPtr <HostNetworkInterface> > resultList;
2356
2357 std::list <ComObjPtr <HostNetworkInterface> >::iterator it;
2358 for (it = allList.begin(); it != allList.end(); ++it)
2359 {
2360 HostNetworkInterfaceType_T t;
2361 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
2362 if(FAILED(hr))
2363 return hr;
2364
2365 if(t == type)
2366 {
2367 (*it)->setVirtualBox(mParent);
2368 resultList.push_back (*it);
2369 }
2370 }
2371
2372 SafeIfaceArray <IHostNetworkInterface> filteredNetworkInterfaces (resultList);
2373 filteredNetworkInterfaces.detachTo (ComSafeArrayOutArg (aNetworkInterfaces));
2374
2375 return S_OK;
2376}
2377
2378STDMETHODIMP Host::FindUSBDeviceByAddress (IN_BSTR aAddress, IHostUSBDevice **aDevice)
2379{
2380#ifdef VBOX_WITH_USB
2381 CheckComArgNotNull(aAddress);
2382 CheckComArgOutPointerValid(aDevice);
2383
2384 *aDevice = NULL;
2385
2386 SafeIfaceArray <IHostUSBDevice> devsvec;
2387 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
2388 CheckComRCReturnRC (rc);
2389
2390 for (size_t i = 0; i < devsvec.size(); ++i)
2391 {
2392 Bstr address;
2393 rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
2394 CheckComRCReturnRC (rc);
2395 if (address == aAddress)
2396 {
2397 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo (aDevice);
2398 }
2399 }
2400
2401 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
2402 "Could not find a USB device with address '%ls'"),
2403 aAddress);
2404
2405#else /* !VBOX_WITH_USB */
2406 NOREF(aAddress);
2407 NOREF(aDevice);
2408 return E_NOTIMPL;
2409#endif /* !VBOX_WITH_USB */
2410}
2411
2412STDMETHODIMP Host::FindUSBDeviceById (IN_BSTR aId, IHostUSBDevice **aDevice)
2413{
2414#ifdef VBOX_WITH_USB
2415 CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
2416 CheckComArgOutPointerValid(aDevice);
2417
2418 *aDevice = NULL;
2419
2420 SafeIfaceArray <IHostUSBDevice> devsvec;
2421 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
2422 CheckComRCReturnRC (rc);
2423
2424 for (size_t i = 0; i < devsvec.size(); ++i)
2425 {
2426 Bstr id;
2427 rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
2428 CheckComRCReturnRC (rc);
2429 if (id == aId)
2430 {
2431 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo (aDevice);
2432 }
2433 }
2434
2435 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
2436 "Could not find a USB device with uuid {%RTuuid}"),
2437 Guid (aId).raw());
2438
2439#else /* !VBOX_WITH_USB */
2440 NOREF(aId);
2441 NOREF(aDevice);
2442 return E_NOTIMPL;
2443#endif /* !VBOX_WITH_USB */
2444}
2445
2446
2447/* 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