VirtualBox

source: vbox/trunk/src/VBox/Main/linux/HostHardwareLinux.cpp@ 16093

Last change on this file since 16093 was 16093, checked in by vboxsync, 16 years ago

Main: try to get the USB enumeration right on RHEL5, again

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 46.6 KB
Line 
1/* $Id: HostHardwareLinux.cpp 16093 2009-01-20 17:04:08Z vboxsync $ */
2/** @file
3 * Classes for handling hardware detection under Linux. Please feel free to
4 * expand these to work for other systems (Solaris!) or to add new ones for
5 * other systems.
6 */
7
8/*
9 * Copyright (C) 2008 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.215389.xyz. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24#define LOG_GROUP LOG_GROUP_MAIN
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29
30#include <HostHardwareLinux.h>
31
32#include <VBox/log.h>
33
34#include <iprt/env.h>
35#include <iprt/mem.h>
36#include <iprt/string.h>
37
38#ifdef RT_OS_LINUX
39# include <sys/types.h>
40# include <sys/stat.h>
41# include <unistd.h>
42# include <sys/ioctl.h>
43# include <fcntl.h>
44# include <mntent.h>
45/* bird: This is a hack to work around conflicts between these linux kernel headers
46 * and the GLIBC tcpip headers. They have different declarations of the 4
47 * standard byte order functions. */
48// # define _LINUX_BYTEORDER_GENERIC_H
49# define _LINUX_BYTEORDER_SWABB_H
50# include <linux/cdrom.h>
51# ifdef VBOX_WITH_DBUS
52# include <vbox-dbus.h>
53# endif
54# include <errno.h>
55#endif /* RT_OS_LINUX */
56
57/*******************************************************************************
58* Global Variables *
59*******************************************************************************/
60
61bool g_testHostHardwareLinux = false;
62static bool testing () { return g_testHostHardwareLinux; }
63
64/*******************************************************************************
65* Typedefs and Defines *
66*******************************************************************************/
67
68/** When waiting for hotplug events, we currently restart the wait after at
69 * most this many milliseconds. */
70enum { DBUS_POLL_TIMEOUT = 2000 /* ms */ };
71
72
73static bool validateDevice(const char *deviceNode, bool isDVD);
74static int getDriveInfoFromEnv(const char *pszVar, DriveInfoList *pList,
75 bool isDVD, bool *pfSuccess);
76static int getDVDInfoFromMTab(char *mountTable, DriveInfoList *pList);
77#ifdef VBOX_WITH_DBUS
78/* These must be extern to be usable in the RTMemAutoPtr template */
79extern void VBoxHalShutdown (DBusConnection *pConnection);
80extern void VBoxHalShutdownPrivate (DBusConnection *pConnection);
81
82static int halInit(RTMemAutoPtr <DBusConnection, VBoxHalShutdown> *pConnection);
83static int halInitPrivate(RTMemAutoPtr <DBusConnection, VBoxHalShutdownPrivate> *pConnection);
84static int halFindDeviceStringMatch (DBusConnection *pConnection,
85 const char *pszKey, const char *pszValue,
86 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage);
87static bool dbusMessageIsNonEmptyArray(DBusMessage *pMessage);
88static int halGetPropertyStrings (DBusConnection *pConnection,
89 const char *pszUdi, size_t cKeys,
90 const char **papszKeys, char **papszValues,
91 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage);
92static int getDriveInfoFromHal(DriveInfoList *pList, bool isDVD,
93 bool *pfSuccess);
94static int getUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess);
95static int getOldUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess);
96static int getUSBInterfacesFromHal(std::vector <std::string> *pList,
97 const char *pcszUdi, bool *pfSuccess);
98static DBusHandlerResult dbusFilterFunction (DBusConnection *pConnection,
99 DBusMessage *pMessage, void *pvUser);
100#endif /* VBOX_WITH_DBUS */
101
102int VBoxMainDriveInfo::updateDVDs ()
103{
104 LogFlowThisFunc (("entered\n"));
105 int rc = VINF_SUCCESS;
106 bool success = false; /* Have we succeeded in finding anything yet? */
107 try
108 {
109 mDVDList.clear ();
110#if defined(RT_OS_LINUX)
111#ifdef VBOX_WITH_DBUS
112 if (RT_SUCCESS (rc) && VBoxDBusCheckPresence() && (!success || testing()))
113 rc = getDriveInfoFromHal(&mDVDList, true /* isDVD */, &success);
114#endif /* VBOX_WITH_DBUS defined */
115 // On Linux without hal, the situation is much more complex. We will take a
116 // heuristical approach and also allow the user to specify a list of host
117 // CDROMs using an environment variable.
118 // The general strategy is to try some known device names and see of they
119 // exist. At last, we'll enumerate the /etc/fstab file (luckily there's an
120 // API to parse it) for CDROM devices. Ok, let's start!
121 if (RT_SUCCESS (rc) && (!success || testing()))
122 rc = getDriveInfoFromEnv ("VBOX_CDROM", &mDVDList, true /* isDVD */,
123 &success);
124 if (RT_SUCCESS (rc) && (!success || testing()))
125 {
126 // this is a good guess usually
127 if (validateDevice("/dev/cdrom", true))
128 mDVDList.push_back (DriveInfo ("/dev/cdrom"));
129
130 // check the mounted drives
131 rc = getDVDInfoFromMTab((char*)"/etc/mtab", &mDVDList);
132
133 // check the drives that can be mounted
134 if (RT_SUCCESS (rc))
135 rc = getDVDInfoFromMTab((char*)"/etc/fstab", &mDVDList);
136 }
137#endif
138 }
139 catch (std::bad_alloc)
140 {
141 rc = VERR_NO_MEMORY;
142 }
143 LogFlowThisFunc (("rc=%Rrc\n", rc));
144 return rc;
145}
146
147int VBoxMainDriveInfo::updateFloppies ()
148{
149 LogFlowThisFunc (("entered\n"));
150 int rc = VINF_SUCCESS;
151 bool success = false; /* Have we succeeded in finding anything yet? */
152 try
153 {
154 mFloppyList.clear ();
155#if defined(RT_OS_LINUX)
156#ifdef VBOX_WITH_DBUS
157 if (RT_SUCCESS (rc) && VBoxDBusCheckPresence() && (!success || testing()))
158 rc = getDriveInfoFromHal(&mFloppyList, false /* isDVD */, &success);
159#endif /* VBOX_WITH_DBUS defined */
160 // As with the CDROMs, on Linux we have to take a multi-level approach
161 // involving parsing the mount tables. As this is not bulletproof, we'll
162 // give the user the chance to override the detection by an environment
163 // variable and skip the detection.
164 if (RT_SUCCESS (rc) && (!success || testing()))
165 rc = getDriveInfoFromEnv ("VBOX_FLOPPY", &mFloppyList, false /* isDVD */,
166 &success);
167
168 if (RT_SUCCESS (rc) && (!success || testing()))
169 {
170 // we assume that a floppy is always /dev/fd[x] with x from 0 to 7
171 char devName[10];
172 for (int i = 0; i <= 7; i++)
173 {
174 sprintf(devName, "/dev/fd%d", i);
175 if (validateDevice(devName, false))
176 mFloppyList.push_back (DriveInfo (devName));
177 }
178 }
179#endif
180 }
181 catch (std::bad_alloc)
182 {
183 rc = VERR_NO_MEMORY;
184 }
185 LogFlowThisFunc (("rc=%Rrc\n", rc));
186 return rc;
187}
188
189int VBoxMainUSBDeviceInfo::UpdateDevices ()
190{
191 LogFlowThisFunc (("entered\n"));
192 int rc = VINF_SUCCESS;
193 bool success = false; /* Have we succeeded in finding anything yet? */
194 try
195 {
196 mDeviceList.clear();
197#if defined(RT_OS_LINUX)
198#ifdef VBOX_WITH_DBUS
199 if (RT_SUCCESS (rc) && VBoxDBusCheckPresence() && (!success || testing()))
200 rc = getUSBDeviceInfoFromHal(&mDeviceList, &success);
201 if (RT_SUCCESS (rc) && VBoxDBusCheckPresence() && (!success || testing()))
202 rc = getOldUSBDeviceInfoFromHal(&mDeviceList, &success);
203#endif /* VBOX_WITH_DBUS defined */
204#endif /* RT_OS_LINUX */
205 }
206 catch (std::bad_alloc)
207 {
208 rc = VERR_NO_MEMORY;
209 }
210 LogFlowThisFunc (("rc=%Rrc\n", rc));
211 return rc;
212}
213
214struct VBoxMainHotplugWaiter::Context
215{
216#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
217 /** The connection to DBus */
218 RTMemAutoPtr <DBusConnection, VBoxHalShutdownPrivate> mConnection;
219 /** Semaphore which is set when a device is hotplugged and reset when
220 * it is read. */
221 bool mTriggered;
222 /** A flag to say that we wish to interrupt the current wait. */
223 bool mInterrupt;
224#endif /* defined RT_OS_LINUX && defined VBOX_WITH_DBUS */
225};
226
227/* This constructor sets up a private connection to the DBus daemon, connects
228 * to the hal service and installs a filter which sets the mTriggered flag in
229 * the Context structure when a device (not necessarily USB) is added or
230 * removed. */
231VBoxMainHotplugWaiter::VBoxMainHotplugWaiter ()
232{
233#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
234 int rc = VINF_SUCCESS;
235
236 if (VBoxDBusCheckPresence())
237 {
238 mContext = new Context;
239 for (unsigned i = 0; RT_SUCCESS(rc) && i < 5 && !mContext->mConnection; ++i)
240 {
241 rc = halInitPrivate (&mContext->mConnection);
242 }
243 if (!mContext->mConnection)
244 rc = VERR_NOT_SUPPORTED;
245 DBusMessage *pMessage;
246 while ( RT_SUCCESS (rc)
247 && (pMessage = dbus_connection_pop_message (mContext->mConnection.get())) != NULL)
248 dbus_message_unref (pMessage); /* empty the message queue. */
249 if ( RT_SUCCESS (rc)
250 && !dbus_connection_add_filter (mContext->mConnection.get(),
251 dbusFilterFunction,
252 &mContext->mTriggered, NULL))
253 rc = VERR_NO_MEMORY;
254 if (RT_FAILURE (rc))
255 mContext->mConnection.reset();
256 }
257#endif /* defined RT_OS_LINUX && defined VBOX_WITH_DBUS */
258}
259
260/* Destructor */
261VBoxMainHotplugWaiter::~VBoxMainHotplugWaiter ()
262{
263#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
264 if (!!mContext->mConnection)
265 dbus_connection_remove_filter (mContext->mConnection.get(), dbusFilterFunction,
266 &mContext->mTriggered);
267 delete mContext;
268#endif /* defined RT_OS_LINUX && defined VBOX_WITH_DBUS */
269}
270
271/* Currently this is implemented using a timed out wait on our private DBus
272 * connection. Because the connection is private we don't have to worry about
273 * blocking other users. */
274int VBoxMainHotplugWaiter::Wait(unsigned cMillies)
275{
276 int rc = VINF_SUCCESS;
277#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
278 if (!mContext->mConnection)
279 rc = VERR_NOT_SUPPORTED;
280 bool connected = true;
281 mContext->mTriggered = false;
282 mContext->mInterrupt = false;
283 unsigned cRealMillies;
284 if (cMillies != RT_INDEFINITE_WAIT)
285 cRealMillies = cMillies;
286 else
287 cRealMillies = DBUS_POLL_TIMEOUT;
288 while ( RT_SUCCESS (rc) && connected && !mContext->mTriggered
289 && !mContext->mInterrupt)
290 {
291 connected = dbus_connection_read_write_dispatch (mContext->mConnection.get(),
292 cRealMillies);
293 if (cMillies != RT_INDEFINITE_WAIT)
294 mContext->mInterrupt = true;
295 }
296 if (!connected)
297 rc = VERR_TRY_AGAIN;
298#else /* !(defined RT_OS_LINUX && defined VBOX_WITH_DBUS) */
299 rc = VERR_NOT_IMPLEMENTED;
300#endif /* !(defined RT_OS_LINUX && defined VBOX_WITH_DBUS) */
301 return rc;
302}
303
304/* Set a flag to tell the Wait not to resume next time it times out. */
305void VBoxMainHotplugWaiter::Interrupt()
306{
307#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
308 mContext->mInterrupt = true;
309#endif /* defined RT_OS_LINUX && defined VBOX_WITH_DBUS */
310}
311
312#ifdef RT_OS_LINUX
313/**
314 * Helper function to check whether the given device node is a valid drive
315 */
316/* static */
317bool validateDevice(const char *deviceNode, bool isDVD)
318{
319 AssertReturn(VALID_PTR (deviceNode), VERR_INVALID_POINTER);
320 LogFlowFunc (("deviceNode=%s, isDVD=%d\n", deviceNode, isDVD));
321 struct stat statInfo;
322 bool retValue = false;
323
324 // sanity check
325 if (!deviceNode)
326 {
327 return false;
328 }
329
330 // first a simple stat() call
331 if (stat(deviceNode, &statInfo) < 0)
332 {
333 return false;
334 } else
335 {
336 if (isDVD)
337 {
338 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
339 {
340 int fileHandle;
341 // now try to open the device
342 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
343 if (fileHandle >= 0)
344 {
345 cdrom_subchnl cdChannelInfo;
346 cdChannelInfo.cdsc_format = CDROM_MSF;
347 // this call will finally reveal the whole truth
348#ifdef RT_OS_LINUX
349 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
350 (errno == EIO) || (errno == ENOENT) ||
351 (errno == EINVAL) || (errno == ENOMEDIUM))
352#endif
353 {
354 retValue = true;
355 }
356 close(fileHandle);
357 }
358 }
359 } else
360 {
361 // floppy case
362 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
363 {
364 /// @todo do some more testing, maybe a nice IOCTL!
365 retValue = true;
366 }
367 }
368 }
369 LogFlowFunc (("retValue=%d\n", retValue));
370 return retValue;
371}
372#else /* !RT_OS_LINUX */
373# error Port me! Copying code over from HostImpl.cpp should be most of the job though.
374#endif /* !RT_OS_LINUX */
375
376/**
377 * Extract the names of drives from an environment variable and add them to a
378 * list if they are valid.
379 * @returns iprt status code
380 * @param pszVar the name of the environment variable. The variable
381 * value should be a list of device node names, separated
382 * by ':' characters.
383 * @param pList the list to append the drives found to
384 * @param isDVD are we looking for DVD drives or for floppies?
385 * @param pfSuccess this will be set to true if we found at least one drive
386 * and to false otherwise. Optional.
387 */
388/* static */
389int getDriveInfoFromEnv(const char *pszVar, DriveInfoList *pList,
390 bool isDVD, bool *pfSuccess)
391{
392 AssertReturn( VALID_PTR (pszVar) && VALID_PTR (pList)
393 && (pfSuccess == NULL || VALID_PTR (pfSuccess)),
394 VERR_INVALID_POINTER);
395 LogFlowFunc (("pszVar=%s, pList=%p, isDVD=%d, pfSuccess=%p\n", pszVar,
396 pList, isDVD, pfSuccess));
397 int rc = VINF_SUCCESS;
398 bool success = false;
399 RTMemAutoPtr<char, RTStrFree> drive;
400 const char *pszValue = RTEnvGet (pszVar);
401 if (pszValue != NULL)
402 {
403 drive = RTStrDup (pszValue);
404 if (!drive)
405 rc = VERR_NO_MEMORY;
406 }
407 if (pszValue != NULL && RT_SUCCESS (rc))
408 {
409 char *pDrive = drive.get();
410 char *pDriveNext = strchr (pDrive, ':');
411 while (pDrive != NULL && *pDrive != '\0')
412 {
413 if (pDriveNext != NULL)
414 *pDriveNext = '\0';
415 if (validateDevice(pDrive, isDVD))
416 {
417 pList->push_back (DriveInfo (pDrive));
418 success = true;
419 }
420 if (pDriveNext != NULL)
421 {
422 pDrive = pDriveNext + 1;
423 pDriveNext = strchr (pDrive, ':');
424 }
425 else
426 pDrive = NULL;
427 }
428 }
429 if (pfSuccess != NULL)
430 *pfSuccess = success;
431 LogFlowFunc (("rc=%Rrc, success=%d\n", rc, success));
432 return rc;
433}
434
435#ifdef RT_OS_LINUX
436/**
437 * Helper function to parse the given mount file and add found entries
438 */
439/* static */
440int getDVDInfoFromMTab(char *mountTable, DriveInfoList *pList)
441{
442 AssertReturn(VALID_PTR (mountTable) && VALID_PTR (pList),
443 VERR_INVALID_POINTER);
444#ifdef RT_OS_LINUX
445 LogFlowFunc (("mountTable=%s, pList=%p\n", mountTable, pList));
446 int rc = VINF_SUCCESS;
447 FILE *mtab = setmntent(mountTable, "r");
448 if (mtab)
449 {
450 struct mntent *mntent;
451 RTMemAutoPtr <char, RTStrFree> mnt_type, mnt_dev;
452 char *tmp;
453 while (RT_SUCCESS (rc) && (mntent = getmntent(mtab)))
454 {
455 mnt_type = RTStrDup (mntent->mnt_type);
456 mnt_dev = RTStrDup (mntent->mnt_fsname);
457 if (!mnt_type || !mnt_dev)
458 rc = VERR_NO_MEMORY;
459 // supermount fs case
460 if (RT_SUCCESS (rc) && strcmp(mnt_type.get(), "supermount") == 0)
461 {
462 tmp = strstr(mntent->mnt_opts, "fs=");
463 if (tmp)
464 {
465 mnt_type = RTStrDup(tmp + strlen("fs="));
466 if (!mnt_type)
467 rc = VERR_NO_MEMORY;
468 else
469 {
470 tmp = strchr(mnt_type.get(), ',');
471 if (tmp)
472 *tmp = '\0';
473 }
474 }
475 tmp = strstr(mntent->mnt_opts, "dev=");
476 if (tmp)
477 {
478 mnt_dev = RTStrDup(tmp + strlen("dev="));
479 if (!mnt_dev)
480 rc = VERR_NO_MEMORY;
481 else
482 {
483 tmp = strchr(mnt_dev.get(), ',');
484 if (tmp)
485 *tmp = '\0';
486 }
487 }
488 }
489 // use strstr here to cover things fs types like "udf,iso9660"
490 if (RT_SUCCESS (rc) && strstr(mnt_type.get(), "iso9660") == 0)
491 {
492 if (validateDevice(mnt_dev.get(), true))
493 {
494 bool insert = true;
495 struct stat srcInfo;
496 if (stat (mnt_dev.get(), &srcInfo) < 0)
497 insert = false;
498 for (DriveInfoList::const_iterator it = pList->begin();
499 insert && it != pList->end(); ++it)
500 {
501 struct stat destInfo;
502 if ( (stat (it->mDevice.c_str(), &destInfo) == 0)
503 && (srcInfo.st_rdev == destInfo.st_rdev))
504 insert = false;
505 }
506 if (insert)
507 pList->push_back (DriveInfo (mnt_dev.get()));
508 }
509 }
510 }
511 endmntent(mtab);
512 }
513 return rc;
514#endif
515}
516
517#endif /* RT_OS_LINUX */
518
519#if defined(RT_OS_LINUX) && defined(VBOX_WITH_DBUS)
520/** Wrapper class around DBusError for automatic cleanup */
521class autoDBusError
522{
523 DBusError mError;
524public:
525 autoDBusError () { dbus_error_init (&mError); }
526 ~autoDBusError ()
527 {
528 if (IsSet())
529 dbus_error_free (&mError);
530 }
531 DBusError &get () { return mError; }
532 bool IsSet ()
533 {
534 Assert ((mError.name == NULL) == (mError.message == NULL));
535 return (mError.name != NULL);
536 }
537 bool HasName (const char *pszName)
538 {
539 Assert ((mError.name == NULL) == (mError.message == NULL));
540 return (RTStrCmp (mError.name, pszName) == 0);
541 }
542 void FlowLog ()
543 {
544 if (IsSet ())
545 LogFlow(("DBus error %s: %s\n", mError.name, mError.message));
546 }
547};
548
549/**
550 * Helper function for setting up a connection to the DBus daemon and
551 * registering with the hal service.
552 *
553 * @note If libdbus is being loaded at runtime then be sure to call
554 * VBoxDBusCheckPresence before calling this.
555 * @returns iprt status code
556 * @param ppConnection where to store the connection handle
557 */
558/* static */
559int halInit (RTMemAutoPtr <DBusConnection, VBoxHalShutdown> *pConnection)
560{
561 AssertReturn(VALID_PTR (pConnection), VERR_INVALID_POINTER);
562 LogFlowFunc (("pConnection=%p\n", pConnection));
563 int rc = VINF_SUCCESS;
564 bool halSuccess = true;
565 autoDBusError dbusError;
566
567 RTMemAutoPtr <DBusConnection, VBoxDBusConnectionUnref> dbusConnection;
568 dbusConnection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbusError.get());
569 if (!dbusConnection)
570 halSuccess = false;
571 if (halSuccess)
572 {
573 dbus_connection_set_exit_on_disconnect (dbusConnection.get(), false);
574 halSuccess = dbus_bus_name_has_owner (dbusConnection.get(),
575 "org.freedesktop.Hal", &dbusError.get());
576 }
577 if (halSuccess)
578 {
579 dbus_bus_add_match (dbusConnection.get(),
580 "type='signal',"
581 "interface='org.freedesktop.Hal.Manager',"
582 "sender='org.freedesktop.Hal',"
583 "path='/org/freedesktop/Hal/Manager'",
584 &dbusError.get());
585 halSuccess = !dbusError.IsSet();
586 }
587 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))
588 rc = VERR_NO_MEMORY;
589 if (halSuccess)
590 *pConnection = dbusConnection.release();
591 LogFlowFunc(("rc=%Rrc, (*pConnection).get()=%p\n", rc, (*pConnection).get()));
592 dbusError.FlowLog();
593 return rc;
594}
595
596/**
597 * Helper function for setting up a private connection to the DBus daemon and
598 * registering with the hal service. Private connections are considered
599 * unsociable and should not be used unnecessarily (as per the DBus API docs).
600 *
601 * @note If libdbus is being loaded at runtime then be sure to call
602 * VBoxDBusCheckPresence before calling this.
603 * @returns iprt status code
604 * @param pConnection where to store the connection handle
605 */
606/* static */
607int halInitPrivate (RTMemAutoPtr <DBusConnection, VBoxHalShutdownPrivate> *pConnection)
608{
609 AssertReturn(VALID_PTR (pConnection), VERR_INVALID_POINTER);
610 LogFlowFunc (("pConnection=%p\n", pConnection));
611 int rc = VINF_SUCCESS;
612 bool halSuccess = true;
613 autoDBusError dbusError;
614
615 RTMemAutoPtr <DBusConnection, VBoxDBusConnectionUnref> dbusConnection;
616 dbusConnection = dbus_bus_get_private (DBUS_BUS_SYSTEM, &dbusError.get());
617 if (!dbusConnection)
618 halSuccess = false;
619 if (halSuccess)
620 {
621 dbus_connection_set_exit_on_disconnect (dbusConnection.get(), false);
622 halSuccess = dbus_bus_name_has_owner (dbusConnection.get(),
623 "org.freedesktop.Hal", &dbusError.get());
624 }
625 if (halSuccess)
626 {
627 dbus_bus_add_match (dbusConnection.get(),
628 "type='signal',"
629 "interface='org.freedesktop.Hal.Manager',"
630 "sender='org.freedesktop.Hal',"
631 "path='/org/freedesktop/Hal/Manager'",
632 &dbusError.get());
633 halSuccess = !dbusError.IsSet();
634 }
635 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))
636 rc = VERR_NO_MEMORY;
637 if (halSuccess)
638 *pConnection = dbusConnection.release();
639 LogFlowFunc(("rc=%Rrc, (*pConnection).get()=%p\n", rc, (*pConnection).get()));
640 dbusError.FlowLog();
641 return rc;
642}
643
644/**
645 * Helper function for shutting down a connection to DBus and hal.
646 * @param pConnection the connection handle
647 */
648/* static */
649void VBoxHalShutdown (DBusConnection *pConnection)
650{
651 AssertReturnVoid(VALID_PTR (pConnection));
652 LogFlowFunc (("pConnection=%p\n", pConnection));
653 autoDBusError dbusError;
654
655 dbus_bus_remove_match (pConnection,
656 "type='signal',"
657 "interface='org.freedesktop.Hal.Manager',"
658 "sender='org.freedesktop.Hal',"
659 "path='/org/freedesktop/Hal/Manager'",
660 &dbusError.get());
661 dbus_connection_unref (pConnection);
662 LogFlowFunc(("returning\n"));
663 dbusError.FlowLog();
664}
665
666/**
667 * Helper function for shutting down a private connection to DBus and hal.
668 * @param pConnection the connection handle
669 */
670/* static */
671void VBoxHalShutdownPrivate (DBusConnection *pConnection)
672{
673 AssertReturnVoid(VALID_PTR (pConnection));
674 LogFlowFunc (("pConnection=%p\n", pConnection));
675 autoDBusError dbusError;
676
677 dbus_bus_remove_match (pConnection,
678 "type='signal',"
679 "interface='org.freedesktop.Hal.Manager',"
680 "sender='org.freedesktop.Hal',"
681 "path='/org/freedesktop/Hal/Manager'",
682 &dbusError.get());
683 dbus_connection_close (pConnection);
684 dbus_connection_unref (pConnection);
685 LogFlowFunc(("returning\n"));
686 dbusError.FlowLog();
687}
688
689/**
690 * Find the UDIs of hal entries that contain Key=Value property.
691 * @returns iprt status code. If a non-fatal error occurs, we return success
692 * but reset pMessage to NULL.
693 * @param pConnection an initialised connection DBus
694 * @param pszKey the property key
695 * @param pszValue the property value
696 * @param pMessage where to store the return DBus message. This must be
697 * parsed to get at the UDIs. NOT optional.
698 */
699/* static */
700int halFindDeviceStringMatch (DBusConnection *pConnection, const char *pszKey,
701 const char *pszValue,
702 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage)
703{
704 AssertReturn( VALID_PTR (pConnection) && VALID_PTR (pszKey)
705 && VALID_PTR (pszValue) && VALID_PTR (pMessage),
706 VERR_INVALID_POINTER);
707 LogFlowFunc (("pConnection=%p, pszKey=%s, pszValue=%s, pMessage=%p\n",
708 pConnection, pszKey, pszValue, pMessage));
709 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */
710 bool halSuccess = true; /* We set this to false to abort the operation. */
711 autoDBusError dbusError;
712
713 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, reply;
714 if (halSuccess && RT_SUCCESS (rc))
715 {
716 message = dbus_message_new_method_call ("org.freedesktop.Hal",
717 "/org/freedesktop/Hal/Manager",
718 "org.freedesktop.Hal.Manager",
719 "FindDeviceStringMatch");
720 if (!message)
721 rc = VERR_NO_MEMORY;
722 }
723 if (halSuccess && RT_SUCCESS (rc))
724 {
725 DBusMessageIter iterAppend;
726 dbus_message_iter_init_append (message.get(), &iterAppend);
727 dbus_message_iter_append_basic (&iterAppend, DBUS_TYPE_STRING, &pszKey);
728 dbus_message_iter_append_basic (&iterAppend, DBUS_TYPE_STRING, &pszValue);
729 reply = dbus_connection_send_with_reply_and_block (pConnection,
730 message.get(), -1,
731 &dbusError.get());
732 if (!reply)
733 halSuccess = false;
734 }
735 *pMessage = reply.release ();
736 LogFlowFunc (("rc=%Rrc, *pMessage.value()=%p\n", rc, (*pMessage).get()));
737 dbusError.FlowLog();
738 return rc;
739}
740
741/**
742 * Checks whether a message is a non-empty array or something else.
743 * @returns true if it is, false otherwise.
744 */
745/* static */
746bool dbusMessageIsNonEmptyArray(DBusMessage *pMessage)
747{
748 bool fSuccess = true;
749 DBusMessageIter iterArray, iterItems;
750 dbus_message_iter_init (pMessage, &iterArray);
751 if (dbus_message_iter_get_arg_type (&iterArray) != DBUS_TYPE_ARRAY)
752 fSuccess = false;
753 if (fSuccess)
754 dbus_message_iter_recurse (&iterArray, &iterItems);
755 if (fSuccess && dbus_message_iter_get_arg_type (&iterItems) == DBUS_TYPE_INVALID)
756 fSuccess = false;
757 return fSuccess;
758}
759
760/**
761 * Read a set of string properties for a device. If some of the properties are
762 * not of type DBUS_TYPE_STRING then a NULL pointer will be returned for them.
763 * @returns iprt status code. If the operation failed for non-fatal reasons
764 * then we return success and leave pMessage untouched - reset it
765 * before the call to detect this.
766 * @param pConnection an initialised connection DBus
767 * @param pszUdi the Udi of the device
768 * @param cProps the number of property values to look up
769 * @param papszKeys the keys of the properties to be looked up
770 * @param papszValues where to store the values of the properties. The
771 * strings returned will be valid until the message
772 * returned in @a ppMessage is freed. Undefined if
773 * the message is NULL.
774 * @param pMessage where to store the return DBus message. The caller
775 * is responsible for freeing this once they have
776 * finished with the value strings. NOT optional.
777 */
778/* static */
779int halGetPropertyStrings (DBusConnection *pConnection, const char *pszUdi,
780 size_t cProps, const char **papszKeys,
781 char **papszValues,
782 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage)
783{
784 AssertReturn( VALID_PTR (pConnection) && VALID_PTR (pszUdi)
785 && VALID_PTR (papszKeys) && VALID_PTR (papszValues)
786 && VALID_PTR (pMessage),
787 VERR_INVALID_POINTER);
788 LogFlowFunc (("pConnection=%p, pszUdi=%s, cProps=%llu, papszKeys=%p, papszValues=%p, pMessage=%p\n",
789 pConnection, pszUdi, cProps, papszKeys, papszValues, pMessage));
790 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */
791 bool halSuccess = true; /* We set this to false to abort the operation. */
792 autoDBusError dbusError;
793
794 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, reply;
795 DBusMessageIter iterGet, iterProps, iterKey, iterValue;
796
797 /* Initialise the return array to NULLs */
798 for (size_t i = 0; i < cProps; ++i)
799 papszValues[i] = NULL;
800
801 /* Send a GetAllProperties message to hald */
802 message = dbus_message_new_method_call ("org.freedesktop.Hal", pszUdi,
803 "org.freedesktop.Hal.Device",
804 "GetAllProperties");
805 if (!message)
806 rc = VERR_NO_MEMORY;
807 if (halSuccess && RT_SUCCESS (rc))
808 {
809 reply = dbus_connection_send_with_reply_and_block (pConnection,
810 message.get(), -1,
811 &dbusError.get());
812 if (!reply)
813 halSuccess = false;
814 }
815
816 /* Parse the reply */
817 if (halSuccess && RT_SUCCESS (rc))
818 {
819 dbus_message_iter_init (reply.get(), &iterGet);
820 if ( dbus_message_iter_get_arg_type (&iterGet) != DBUS_TYPE_ARRAY
821 && dbus_message_iter_get_element_type (&iterGet) != DBUS_TYPE_DICT_ENTRY)
822 halSuccess = false;
823 }
824 if (halSuccess && RT_SUCCESS (rc))
825 dbus_message_iter_recurse (&iterGet, &iterProps);
826 /* Go through all entries in the reply and see if any match our keys. */
827 while ( halSuccess && RT_SUCCESS (rc)
828 && dbus_message_iter_get_arg_type (&iterProps)
829 == DBUS_TYPE_DICT_ENTRY)
830 {
831 const char *pszKey;
832 DBusMessageIter iterEntry, iterValue;
833 dbus_message_iter_recurse (&iterProps, &iterEntry);
834 dbus_message_iter_get_basic (&iterEntry, &pszKey);
835 dbus_message_iter_next (&iterEntry);
836 dbus_message_iter_recurse (&iterEntry, &iterValue);
837 /* Fill in any matches. */
838 for (size_t i = 0; i < cProps; ++i)
839 if (strcmp (pszKey, papszKeys[i]) == 0)
840 {
841 if (dbus_message_iter_get_arg_type (&iterValue) == DBUS_TYPE_STRING)
842 dbus_message_iter_get_basic (&iterValue, &papszValues[i]);
843 }
844 dbus_message_iter_next (&iterProps);
845 }
846 if (RT_SUCCESS (rc) && halSuccess)
847 *pMessage = reply.release();
848 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))
849 rc = VERR_NO_MEMORY;
850 LogFlowFunc (("rc=%Rrc, *pMessage.value()=%p\n", rc, (*pMessage).get()));
851 dbusError.FlowLog();
852 return rc;
853}
854
855/**
856 * Helper function to query the hal subsystem for information about drives
857 * attached to the system.
858 * @returns iprt status code
859 * @param pList where to add information about the drives detected
860 * @param isDVD are we looking for DVDs or floppies?
861 * @param pfSuccess will be set to true if all interactions with hal
862 * succeeded and to false otherwise. Optional.
863 *
864 * @returns IPRT status code
865 */
866/* static */
867int getDriveInfoFromHal(DriveInfoList *pList, bool isDVD, bool *pfSuccess)
868{
869 AssertReturn(VALID_PTR (pList) && (pfSuccess == NULL || VALID_PTR (pfSuccess)),
870 VERR_INVALID_POINTER);
871 LogFlowFunc (("pList=%p, isDVD=%d, pfSuccess=%p\n", pList, isDVD, pfSuccess));
872 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */
873 bool halSuccess = true; /* We set this to false to abort the operation. */
874 autoDBusError dbusError;
875
876 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, replyFind, replyGet;
877 RTMemAutoPtr <DBusConnection, VBoxHalShutdown> dbusConnection;
878 DBusMessageIter iterFind, iterUdis;
879
880 rc = halInit (&dbusConnection);
881 if (!dbusConnection)
882 halSuccess = false;
883 if (halSuccess && RT_SUCCESS (rc))
884 {
885 rc = halFindDeviceStringMatch (dbusConnection.get(), "storage.drive_type",
886 isDVD ? "cdrom" : "floppy", &replyFind);
887 if (!replyFind)
888 halSuccess = false;
889 }
890 if (halSuccess && RT_SUCCESS (rc))
891 {
892 dbus_message_iter_init (replyFind.get(), &iterFind);
893 if (dbus_message_iter_get_arg_type (&iterFind) != DBUS_TYPE_ARRAY)
894 halSuccess = false;
895 }
896 if (halSuccess && RT_SUCCESS (rc))
897 dbus_message_iter_recurse (&iterFind, &iterUdis);
898 for (; halSuccess && RT_SUCCESS (rc)
899 && dbus_message_iter_get_arg_type (&iterUdis) == DBUS_TYPE_STRING;
900 dbus_message_iter_next(&iterUdis))
901 {
902 /* Now get all properties from the iterator */
903 const char *pszUdi;
904 dbus_message_iter_get_basic (&iterUdis, &pszUdi);
905 static const char *papszKeys[] =
906 { "block.device", "info.product", "info.vendor" };
907 char *papszValues[RT_ELEMENTS (papszKeys)];
908 rc = halGetPropertyStrings (dbusConnection.get(), pszUdi, RT_ELEMENTS (papszKeys),
909 papszKeys, papszValues, &replyGet);
910 std::string description;
911 const char *pszDevice = papszValues[0], *pszProduct = papszValues[1],
912 *pszVendor = papszValues[2];
913 if (!!replyGet && pszDevice == NULL)
914 halSuccess = false;
915 if (!!replyGet && pszDevice != NULL)
916 {
917 if ((pszVendor != NULL) && (pszVendor[0] != '\0'))
918 (description += pszVendor) += " ";
919 if ((pszProduct != NULL && pszProduct[0] != '\0'))
920 description += pszProduct;
921 pList->push_back (DriveInfo (pszDevice, pszUdi, description));
922 }
923 }
924 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))
925 rc = VERR_NO_MEMORY;
926 if (pfSuccess != NULL)
927 *pfSuccess = halSuccess;
928 LogFlow (("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));
929 dbusError.FlowLog();
930 return rc;
931}
932
933/**
934 * Helper function to query the hal subsystem for information about USB devices
935 * attached to the system.
936 * @returns iprt status code
937 * @param pList where to add information about the devices detected
938 * @param pfSuccess will be set to true if all interactions with hal
939 * succeeded and to false otherwise. Optional.
940 *
941 * @returns IPRT status code
942 */
943/* static */
944int getUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess)
945{
946 AssertReturn(VALID_PTR (pList) && (pfSuccess == NULL || VALID_PTR (pfSuccess)),
947 VERR_INVALID_POINTER);
948 LogFlowFunc (("pList=%p, pfSuccess=%p\n", pList, pfSuccess));
949 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */
950 bool halSuccess = true; /* We set this to false to abort the operation. */
951 autoDBusError dbusError;
952
953 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, replyFind, replyGet;
954 RTMemAutoPtr <DBusConnection, VBoxHalShutdown> dbusConnection;
955 DBusMessageIter iterFind, iterUdis;
956
957 /* Connect to hal */
958 rc = halInit (&dbusConnection);
959 if (!dbusConnection)
960 halSuccess = false;
961 /* Get an array of all devices in the usb_device subsystem */
962 if (halSuccess && RT_SUCCESS (rc))
963 {
964 rc = halFindDeviceStringMatch (dbusConnection.get(), "info.subsystem",
965 "usb_device", &replyFind);
966 if (!replyFind)
967 halSuccess = false;
968 }
969 if (halSuccess && RT_SUCCESS (rc))
970 {
971 dbus_message_iter_init (replyFind.get(), &iterFind);
972 if (dbus_message_iter_get_arg_type (&iterFind) != DBUS_TYPE_ARRAY)
973 halSuccess = false;
974 }
975 /* Recurse down into the array and query interesting information about the
976 * entries. */
977 if (halSuccess && RT_SUCCESS (rc))
978 dbus_message_iter_recurse (&iterFind, &iterUdis);
979 for (; halSuccess && RT_SUCCESS (rc)
980 && dbus_message_iter_get_arg_type (&iterUdis) == DBUS_TYPE_STRING;
981 dbus_message_iter_next(&iterUdis))
982 {
983 /* Get the device node and the sysfs path for the current entry. */
984 const char *pszUdi;
985 dbus_message_iter_get_basic (&iterUdis, &pszUdi);
986 static const char *papszKeys[] = { "linux.device_file", "linux.sysfs_path" };
987 char *papszValues[RT_ELEMENTS (papszKeys)];
988 rc = halGetPropertyStrings (dbusConnection.get(), pszUdi, RT_ELEMENTS (papszKeys),
989 papszKeys, papszValues, &replyGet);
990 std::string description;
991 const char *pszDevice = papszValues[0], *pszSysfsPath = papszValues[1];
992 /* Get the interfaces. */
993 if (!!replyGet && pszDevice && pszSysfsPath)
994 {
995 USBDeviceInfo info (pszDevice, pszSysfsPath);
996 bool ifaceSuccess = true; /* If we can't get the interfaces, just
997 * skip this one device. */
998 rc = getUSBInterfacesFromHal (&info.mInterfaces, pszUdi, &ifaceSuccess);
999 if (RT_SUCCESS(rc) && halSuccess && ifaceSuccess)
1000 pList->push_back (info);
1001 }
1002 }
1003 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))
1004 rc = VERR_NO_MEMORY;
1005 if (pfSuccess != NULL)
1006 *pfSuccess = halSuccess;
1007 LogFlow (("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));
1008 dbusError.FlowLog();
1009 return rc;
1010}
1011
1012/**
1013 * Helper function to query the hal subsystem for information about USB devices
1014 * attached to the system, using the older API.
1015 * @returns iprt status code
1016 * @param pList where to add information about the devices detected
1017 * @param pfSuccess will be set to true if all interactions with hal
1018 * succeeded and to false otherwise. Optional.
1019 *
1020 * @returns IPRT status code
1021 */
1022/* static */
1023int getOldUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess)
1024{
1025 AssertReturn(VALID_PTR (pList) && (pfSuccess == NULL || VALID_PTR (pfSuccess)),
1026 VERR_INVALID_POINTER);
1027 LogFlowFunc (("pList=%p, pfSuccess=%p\n", pList, pfSuccess));
1028 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */
1029 bool halSuccess = true; /* We set this to false to abort the operation. */
1030 autoDBusError dbusError;
1031
1032 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, replyFind, replyGet;
1033 RTMemAutoPtr <DBusConnection, VBoxHalShutdown> dbusConnection;
1034 DBusMessageIter iterFind, iterUdis;
1035
1036 /* Connect to hal */
1037 rc = halInit (&dbusConnection);
1038 if (!dbusConnection)
1039 halSuccess = false;
1040 /* Get an array of all devices in the usb_device subsystem */
1041 if (halSuccess && RT_SUCCESS (rc))
1042 {
1043 rc = halFindDeviceStringMatch (dbusConnection.get(), "info.category",
1044 "usbraw", &replyFind);
1045 if (!replyFind)
1046 halSuccess = false;
1047 }
1048 if (halSuccess && RT_SUCCESS (rc))
1049 {
1050 dbus_message_iter_init (replyFind.get(), &iterFind);
1051 if (dbus_message_iter_get_arg_type (&iterFind) != DBUS_TYPE_ARRAY)
1052 halSuccess = false;
1053 }
1054 /* Recurse down into the array and query interesting information about the
1055 * entries. */
1056 if (halSuccess && RT_SUCCESS (rc))
1057 dbus_message_iter_recurse (&iterFind, &iterUdis);
1058 for (; halSuccess && RT_SUCCESS (rc)
1059 && dbus_message_iter_get_arg_type (&iterUdis) == DBUS_TYPE_STRING;
1060 dbus_message_iter_next(&iterUdis))
1061 {
1062 /* Get the device node and the sysfs path for the current entry. */
1063 const char *pszUdi;
1064 dbus_message_iter_get_basic (&iterUdis, &pszUdi);
1065 static const char *papszKeys[] = { "linux.device_file", "linux.sysfs_path",
1066 "info.parent" };
1067 char *papszValues[RT_ELEMENTS (papszKeys)];
1068 rc = halGetPropertyStrings (dbusConnection.get(), pszUdi, RT_ELEMENTS (papszKeys),
1069 papszKeys, papszValues, &replyGet);
1070 std::string description;
1071 const char *pszDevice = papszValues[0], *pszSysfsPath = papszValues[1],
1072 *pszParent = papszValues[2];
1073 /* Get the interfaces. */
1074 if (!!replyGet && pszDevice && pszSysfsPath)
1075 {
1076 USBDeviceInfo info (pszDevice, pszSysfsPath);
1077 bool ifaceSuccess = true; /* If we can't get the interfaces, just
1078 * skip this one device. */
1079 rc = getUSBInterfacesFromHal (&info.mInterfaces, pszParent, &ifaceSuccess);
1080 if (RT_SUCCESS(rc) && halSuccess && ifaceSuccess)
1081 pList->push_back (info);
1082 }
1083 }
1084 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))
1085 rc = VERR_NO_MEMORY;
1086 if (pfSuccess != NULL)
1087 *pfSuccess = halSuccess;
1088 LogFlow (("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));
1089 dbusError.FlowLog();
1090 return rc;
1091}
1092
1093/**
1094 * Helper function to query the hal subsystem for information about USB devices
1095 * attached to the system.
1096 * @returns iprt status code
1097 * @param pList where to add information about the devices detected. If
1098 * certain interfaces are not found (@a pfFound is false on
1099 * return) this may contain invalid information.
1100 * @param pcszUdi the hal UDI of the device
1101 * @param pfSuccess will be set to true if the operation succeeds and to
1102 * false if it fails for non-critical reasons. Optional.
1103 *
1104 * @returns IPRT status code
1105 */
1106/* static */
1107int getUSBInterfacesFromHal(std::vector <std::string> *pList,
1108 const char *pcszUdi, bool *pfSuccess)
1109{
1110 AssertReturn(VALID_PTR (pList) && VALID_PTR (pcszUdi) &&
1111 (pfSuccess == NULL || VALID_PTR (pfSuccess)),
1112 VERR_INVALID_POINTER);
1113 LogFlowFunc (("pList=%p, pcszUdi=%s, pfSuccess=%p\n", pList, pcszUdi,
1114 pfSuccess));
1115 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */
1116 bool halSuccess = true; /* We set this to false to abort the operation. */
1117 autoDBusError dbusError;
1118
1119 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, replyFind, replyGet;
1120 RTMemAutoPtr <DBusConnection, VBoxHalShutdown> dbusConnection;
1121 DBusMessageIter iterFind, iterUdis;
1122
1123 rc = halInit (&dbusConnection);
1124 if (!dbusConnection)
1125 halSuccess = false;
1126 if (halSuccess && RT_SUCCESS (rc))
1127 {
1128 /* Look for children of the current UDI. */
1129 rc = halFindDeviceStringMatch (dbusConnection.get(), "info.parent",
1130 pcszUdi, &replyFind);
1131 if (!replyFind)
1132 halSuccess = false;
1133 }
1134 if (halSuccess && RT_SUCCESS (rc))
1135 {
1136 dbus_message_iter_init (replyFind.get(), &iterFind);
1137 if (dbus_message_iter_get_arg_type (&iterFind) != DBUS_TYPE_ARRAY)
1138 halSuccess = false;
1139 }
1140 if (halSuccess && RT_SUCCESS (rc))
1141 dbus_message_iter_recurse (&iterFind, &iterUdis);
1142 for (; halSuccess && RT_SUCCESS (rc)
1143 && dbus_message_iter_get_arg_type (&iterUdis) == DBUS_TYPE_STRING;
1144 dbus_message_iter_next(&iterUdis))
1145 {
1146 /* Now get the sysfs path and the subsystem from the iterator */
1147 const char *pszUdi;
1148 dbus_message_iter_get_basic (&iterUdis, &pszUdi);
1149 static const char *papszKeys[] = { "linux.sysfs_path", "info.subsystem",
1150 "linux.subsystem" };
1151 char *papszValues[RT_ELEMENTS (papszKeys)];
1152 rc = halGetPropertyStrings (dbusConnection.get(), pszUdi, RT_ELEMENTS (papszKeys),
1153 papszKeys, papszValues, &replyGet);
1154 std::string description;
1155 const char *pszSysfsPath = papszValues[0], *pszInfoSubsystem = papszValues[1],
1156 *pszLinuxSubsystem = papszValues[2];
1157 if (!replyGet)
1158 halSuccess = false;
1159 if (!!replyGet && pszSysfsPath == NULL)
1160 halSuccess = false;
1161 if ( halSuccess && RT_SUCCESS (rc)
1162 && RTStrCmp (pszInfoSubsystem, "usb_device") != 0 /* Children of buses can also be devices. */
1163 && RTStrCmp (pszLinuxSubsystem, "usb_device") != 0)
1164 pList->push_back (pszSysfsPath);
1165 }
1166 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))
1167 rc = VERR_NO_MEMORY;
1168 if (pfSuccess != NULL)
1169 *pfSuccess = halSuccess;
1170 LogFlow (("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));
1171 dbusError.FlowLog();
1172 return rc;
1173}
1174
1175/**
1176 * When it is registered with DBus, this function will be called by
1177 * dbus_connection_read_write_dispatch each time a message is received over the
1178 * DBus connection. We check whether that message was caused by a hal device
1179 * hotplug event, and if so we set a flag. dbus_connection_read_write_dispatch
1180 * will return after calling its filter functions, and its caller should then
1181 * check the status of the flag passed to the filter function.
1182 *
1183 * @param pConnection The DBus connection we are using.
1184 * @param pMessage The DBus message which just arrived.
1185 * @param pvUser A pointer to the flag variable we are to set.
1186 */
1187/* static */
1188DBusHandlerResult dbusFilterFunction (DBusConnection *pConnection,
1189 DBusMessage *pMessage, void *pvUser)
1190{
1191 bool *pTriggered = reinterpret_cast<bool *> (pvUser);
1192 if ( dbus_message_is_signal (pMessage, "org.freedesktop.Hal.Manager",
1193 "DeviceAdded")
1194 || dbus_message_is_signal (pMessage, "org.freedesktop.Hal.Manager",
1195 "DeviceRemoved"))
1196 {
1197 *pTriggered = true;
1198 }
1199 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1200}
1201#endif /* RT_OS_LINUX && VBOX_WITH_DBUS */
1202
Note: See TracBrowser for help on using the repository browser.

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