VirtualBox

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

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

Main: more Linux host USB enumeration adjustments

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