Changeset 28315 in vbox
- Timestamp:
- Apr 14, 2010 4:34:00 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/linux/HostHardwareLinux.cpp
r28313 r28315 853 853 } 854 854 855 /**856 * Helper function to query the sysfs subsystem for information about USB857 * devices attached to the system.858 * @returns iprt status code859 * @param pList where to add information about the drives detected860 * @param pfSuccess Did we find anything?861 *862 * @returns IPRT status code863 */864 static int getUSBDeviceInfoFromSysfs(USBDeviceInfoList *pList,865 bool *pfSuccess)866 {867 AssertPtrReturn(pList, VERR_INVALID_POINTER);868 AssertPtrNullReturn(pfSuccess, VERR_INVALID_POINTER); /* Valid or Null */869 LogFlowFunc (("pList=%p, pfSuccess=%p\n",870 pList, pfSuccess));871 size_t cDevices = pList->size();872 matchUSBDevice devHandler(pList);873 int rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", &devHandler);874 do {875 if (RT_FAILURE(rc))876 break;877 for (USBDeviceInfoList::iterator pInfo = pList->begin();878 pInfo != pList->end(); ++pInfo)879 {880 matchUSBInterface ifaceHandler(&*pInfo);881 rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", &ifaceHandler);882 if (RT_FAILURE(rc))883 break;884 }885 } while(0);886 if (RT_FAILURE(rc))887 /* Clean up again */888 while (pList->size() > cDevices)889 pList->pop_back();890 if (pfSuccess)891 *pfSuccess = RT_SUCCESS(rc);892 LogFlow (("rc=%Rrc\n", rc));893 return rc;894 }895 855 896 856 /** Structure for holding information about a drive we have found */ … … 1197 1157 1198 1158 1199 #if defined(RT_OS_LINUX) && defined(VBOX_WITH_DBUS)1200 /** Wrapper class around DBusError for automatic cleanup */1201 class autoDBusError1202 {1203 DBusError mError;1204 public:1205 autoDBusError () { dbus_error_init (&mError); }1206 ~autoDBusError ()1207 {1208 if (IsSet())1209 dbus_error_free (&mError);1210 }1211 DBusError &get () { return mError; }1212 bool IsSet ()1213 {1214 Assert((mError.name == NULL) == (mError.message == NULL));1215 return (mError.name != NULL);1216 }1217 bool HasName (const char *pcszName)1218 {1219 Assert((mError.name == NULL) == (mError.message == NULL));1220 return (RTStrCmp (mError.name, pcszName) == 0);1221 }1222 void FlowLog ()1223 {1224 if (IsSet ())1225 LogFlow(("DBus error %s: %s\n", mError.name, mError.message));1226 }1227 };1228 1229 /**1230 * Helper function for setting up a connection to the DBus daemon and1231 * registering with the hal service.1232 *1233 * @note If libdbus is being loaded at runtime then be sure to call1234 * VBoxDBusCheckPresence before calling this.1235 * @returns iprt status code1236 * @param ppConnection where to store the connection handle1237 */1238 /* static */1239 int halInit (RTMemAutoPtr <DBusConnection, VBoxHalShutdown> *pConnection)1240 {1241 AssertReturn(VALID_PTR (pConnection), VERR_INVALID_POINTER);1242 LogFlowFunc (("pConnection=%p\n", pConnection));1243 int rc = VINF_SUCCESS;1244 bool halSuccess = true;1245 autoDBusError dbusError;1246 1247 RTMemAutoPtr <DBusConnection, VBoxDBusConnectionUnref> dbusConnection;1248 dbusConnection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbusError.get());1249 if (!dbusConnection)1250 halSuccess = false;1251 if (halSuccess)1252 {1253 dbus_connection_set_exit_on_disconnect (dbusConnection.get(), false);1254 halSuccess = dbus_bus_name_has_owner (dbusConnection.get(),1255 "org.freedesktop.Hal", &dbusError.get());1256 }1257 if (halSuccess)1258 {1259 dbus_bus_add_match (dbusConnection.get(),1260 "type='signal',"1261 "interface='org.freedesktop.Hal.Manager',"1262 "sender='org.freedesktop.Hal',"1263 "path='/org/freedesktop/Hal/Manager'",1264 &dbusError.get());1265 halSuccess = !dbusError.IsSet();1266 }1267 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))1268 rc = VERR_NO_MEMORY;1269 if (halSuccess)1270 *pConnection = dbusConnection.release();1271 LogFlowFunc(("rc=%Rrc, (*pConnection).get()=%p\n", rc, (*pConnection).get()));1272 dbusError.FlowLog();1273 return rc;1274 }1275 1276 /**1277 * Helper function for setting up a private connection to the DBus daemon and1278 * registering with the hal service. Private connections are considered1279 * unsociable and should not be used unnecessarily (as per the DBus API docs).1280 *1281 * @note If libdbus is being loaded at runtime then be sure to call1282 * VBoxDBusCheckPresence before calling this.1283 * @returns iprt status code1284 * @param pConnection where to store the connection handle1285 */1286 /* static */1287 int halInitPrivate (RTMemAutoPtr <DBusConnection, VBoxHalShutdownPrivate> *pConnection)1288 {1289 AssertReturn(VALID_PTR (pConnection), VERR_INVALID_POINTER);1290 LogFlowFunc (("pConnection=%p\n", pConnection));1291 int rc = VINF_SUCCESS;1292 bool halSuccess = true;1293 autoDBusError dbusError;1294 1295 RTMemAutoPtr <DBusConnection, VBoxDBusConnectionCloseAndUnref> dbusConnection;1296 dbusConnection = dbus_bus_get_private (DBUS_BUS_SYSTEM, &dbusError.get());1297 if (!dbusConnection)1298 halSuccess = false;1299 if (halSuccess)1300 {1301 dbus_connection_set_exit_on_disconnect (dbusConnection.get(), false);1302 halSuccess = dbus_bus_name_has_owner (dbusConnection.get(),1303 "org.freedesktop.Hal", &dbusError.get());1304 }1305 if (halSuccess)1306 {1307 dbus_bus_add_match (dbusConnection.get(),1308 "type='signal',"1309 "interface='org.freedesktop.Hal.Manager',"1310 "sender='org.freedesktop.Hal',"1311 "path='/org/freedesktop/Hal/Manager'",1312 &dbusError.get());1313 halSuccess = !dbusError.IsSet();1314 }1315 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))1316 rc = VERR_NO_MEMORY;1317 if (halSuccess)1318 *pConnection = dbusConnection.release();1319 LogFlowFunc(("rc=%Rrc, (*pConnection).get()=%p\n", rc, (*pConnection).get()));1320 dbusError.FlowLog();1321 return rc;1322 }1323 1324 /**1325 * Helper function for shutting down a connection to DBus and hal.1326 * @param pConnection the connection handle1327 */1328 /* extern */1329 void VBoxHalShutdown (DBusConnection *pConnection)1330 {1331 AssertReturnVoid(VALID_PTR (pConnection));1332 LogFlowFunc (("pConnection=%p\n", pConnection));1333 autoDBusError dbusError;1334 1335 dbus_bus_remove_match (pConnection,1336 "type='signal',"1337 "interface='org.freedesktop.Hal.Manager',"1338 "sender='org.freedesktop.Hal',"1339 "path='/org/freedesktop/Hal/Manager'",1340 &dbusError.get());1341 dbus_connection_unref (pConnection);1342 LogFlowFunc(("returning\n"));1343 dbusError.FlowLog();1344 }1345 1346 /**1347 * Helper function for shutting down a private connection to DBus and hal.1348 * @param pConnection the connection handle1349 */1350 /* extern */1351 void VBoxHalShutdownPrivate (DBusConnection *pConnection)1352 {1353 AssertReturnVoid(VALID_PTR (pConnection));1354 LogFlowFunc (("pConnection=%p\n", pConnection));1355 autoDBusError dbusError;1356 1357 dbus_bus_remove_match (pConnection,1358 "type='signal',"1359 "interface='org.freedesktop.Hal.Manager',"1360 "sender='org.freedesktop.Hal',"1361 "path='/org/freedesktop/Hal/Manager'",1362 &dbusError.get());1363 dbus_connection_close (pConnection);1364 dbus_connection_unref (pConnection);1365 LogFlowFunc(("returning\n"));1366 dbusError.FlowLog();1367 }1368 1369 /** Wrapper around dbus_connection_unref. We need this to use it as a real1370 * function in auto pointers, as a function pointer won't wash here. */1371 /* extern */1372 void VBoxDBusConnectionUnref(DBusConnection *pConnection)1373 {1374 dbus_connection_unref(pConnection);1375 }1376 1377 /**1378 * This function closes and unrefs a private connection to dbus. It should1379 * only be called once no-one else is referencing the connection.1380 */1381 /* extern */1382 void VBoxDBusConnectionCloseAndUnref(DBusConnection *pConnection)1383 {1384 dbus_connection_close(pConnection);1385 dbus_connection_unref(pConnection);1386 }1387 1388 /** Wrapper around dbus_message_unref. We need this to use it as a real1389 * function in auto pointers, as a function pointer won't wash here. */1390 /* extern */1391 void VBoxDBusMessageUnref(DBusMessage *pMessage)1392 {1393 dbus_message_unref(pMessage);1394 }1395 1396 /**1397 * Find the UDIs of hal entries that contain Key=Value property.1398 * @returns iprt status code. If a non-fatal error occurs, we return success1399 * but reset pMessage to NULL.1400 * @param pConnection an initialised connection DBus1401 * @param pszKey the property key1402 * @param pszValue the property value1403 * @param pMessage where to store the return DBus message. This must be1404 * parsed to get at the UDIs. NOT optional.1405 */1406 /* static */1407 int halFindDeviceStringMatch (DBusConnection *pConnection, const char *pszKey,1408 const char *pszValue,1409 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage)1410 {1411 AssertReturn( VALID_PTR (pConnection) && VALID_PTR (pszKey)1412 && VALID_PTR (pszValue) && VALID_PTR (pMessage),1413 VERR_INVALID_POINTER);1414 LogFlowFunc (("pConnection=%p, pszKey=%s, pszValue=%s, pMessage=%p\n",1415 pConnection, pszKey, pszValue, pMessage));1416 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */1417 bool halSuccess = true; /* We set this to false to abort the operation. */1418 autoDBusError dbusError;1419 1420 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, reply;1421 if (halSuccess && RT_SUCCESS(rc))1422 {1423 message = dbus_message_new_method_call ("org.freedesktop.Hal",1424 "/org/freedesktop/Hal/Manager",1425 "org.freedesktop.Hal.Manager",1426 "FindDeviceStringMatch");1427 if (!message)1428 rc = VERR_NO_MEMORY;1429 }1430 if (halSuccess && RT_SUCCESS(rc))1431 {1432 DBusMessageIter iterAppend;1433 dbus_message_iter_init_append (message.get(), &iterAppend);1434 dbus_message_iter_append_basic (&iterAppend, DBUS_TYPE_STRING, &pszKey);1435 dbus_message_iter_append_basic (&iterAppend, DBUS_TYPE_STRING, &pszValue);1436 reply = dbus_connection_send_with_reply_and_block (pConnection,1437 message.get(), -1,1438 &dbusError.get());1439 if (!reply)1440 halSuccess = false;1441 }1442 *pMessage = reply.release ();1443 LogFlowFunc (("rc=%Rrc, *pMessage.value()=%p\n", rc, (*pMessage).get()));1444 dbusError.FlowLog();1445 return rc;1446 }1447 1448 /**1449 * Find the UDIs of hal entries that contain Key=Value property and return the1450 * result on the end of a vector of iprt::MiniString.1451 * @returns iprt status code. If a non-fatal error occurs, we return success1452 * but set *pfSuccess to false.1453 * @param pConnection an initialised connection DBus1454 * @param pszKey the property key1455 * @param pszValue the property value1456 * @param pMatches pointer to an array of iprt::MiniString to append the1457 * results to. NOT optional.1458 * @param pfSuccess will be set to true if the operation succeeds1459 */1460 /* static */1461 int halFindDeviceStringMatchVector (DBusConnection *pConnection,1462 const char *pszKey, const char *pszValue,1463 std::vector<iprt::MiniString> *pMatches,1464 bool *pfSuccess)1465 {1466 AssertPtrReturn (pConnection, VERR_INVALID_POINTER);1467 AssertPtrReturn (pszKey, VERR_INVALID_POINTER);1468 AssertPtrReturn (pszValue, VERR_INVALID_POINTER);1469 AssertPtrReturn (pMatches, VERR_INVALID_POINTER);1470 AssertReturn(pfSuccess == NULL || VALID_PTR (pfSuccess), VERR_INVALID_POINTER);1471 LogFlowFunc (("pConnection=%p, pszKey=%s, pszValue=%s, pMatches=%p, pfSuccess=%p\n",1472 pConnection, pszKey, pszValue, pMatches, pfSuccess));1473 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */1474 bool halSuccess = true; /* We set this to false to abort the operation. */1475 1476 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, replyFind;1477 DBusMessageIter iterFind, iterUdis;1478 1479 if (halSuccess && RT_SUCCESS(rc))1480 {1481 rc = halFindDeviceStringMatch (pConnection, pszKey, pszValue,1482 &replyFind);1483 if (!replyFind)1484 halSuccess = false;1485 }1486 if (halSuccess && RT_SUCCESS(rc))1487 {1488 dbus_message_iter_init (replyFind.get(), &iterFind);1489 if (dbus_message_iter_get_arg_type (&iterFind) != DBUS_TYPE_ARRAY)1490 halSuccess = false;1491 }1492 if (halSuccess && RT_SUCCESS(rc))1493 dbus_message_iter_recurse (&iterFind, &iterUdis);1494 for (; halSuccess && RT_SUCCESS(rc)1495 && dbus_message_iter_get_arg_type (&iterUdis) == DBUS_TYPE_STRING;1496 dbus_message_iter_next(&iterUdis))1497 {1498 /* Now get all UDIs from the iterator */1499 const char *pszUdi;1500 dbus_message_iter_get_basic (&iterUdis, &pszUdi);1501 try1502 {1503 pMatches->push_back(pszUdi);1504 }1505 catch(std::bad_alloc &e)1506 {1507 rc = VERR_NO_MEMORY;1508 }1509 }1510 if (pfSuccess != NULL)1511 *pfSuccess = halSuccess;1512 LogFlow (("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));1513 return rc;1514 }1515 1516 /**1517 * Read a set of string properties for a device. If some of the properties are1518 * not of type DBUS_TYPE_STRING or do not exist then a NULL pointer will be1519 * returned for them.1520 * @returns iprt status code. If the operation failed for non-fatal reasons1521 * then we return success and leave pMessage untouched - reset it1522 * before the call to detect this.1523 * @param pConnection an initialised connection DBus1524 * @param pszUdi the Udi of the device1525 * @param cProps the number of property values to look up1526 * @param papszKeys the keys of the properties to be looked up1527 * @param papszValues where to store the values of the properties. The1528 * strings returned will be valid until the message1529 * returned in @a ppMessage is freed. Undefined if1530 * the message is NULL.1531 * @param pMessage where to store the return DBus message. The caller1532 * is responsible for freeing this once they have1533 * finished with the value strings. NOT optional.1534 */1535 /* static */1536 int halGetPropertyStrings (DBusConnection *pConnection, const char *pszUdi,1537 size_t cProps, const char **papszKeys,1538 char **papszValues,1539 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage)1540 {1541 AssertReturn( VALID_PTR (pConnection) && VALID_PTR (pszUdi)1542 && VALID_PTR (papszKeys) && VALID_PTR (papszValues)1543 && VALID_PTR (pMessage),1544 VERR_INVALID_POINTER);1545 LogFlowFunc (("pConnection=%p, pszUdi=%s, cProps=%llu, papszKeys=%p, papszValues=%p, pMessage=%p\n",1546 pConnection, pszUdi, cProps, papszKeys, papszValues, pMessage));1547 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */1548 bool halSuccess = true; /* We set this to false to abort the operation. */1549 autoDBusError dbusError;1550 1551 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, reply;1552 DBusMessageIter iterGet, iterProps;1553 1554 /* Initialise the return array to NULLs */1555 for (size_t i = 0; i < cProps; ++i)1556 papszValues[i] = NULL;1557 1558 /* Send a GetAllProperties message to hald */1559 message = dbus_message_new_method_call ("org.freedesktop.Hal", pszUdi,1560 "org.freedesktop.Hal.Device",1561 "GetAllProperties");1562 if (!message)1563 rc = VERR_NO_MEMORY;1564 if (halSuccess && RT_SUCCESS(rc))1565 {1566 reply = dbus_connection_send_with_reply_and_block (pConnection,1567 message.get(), -1,1568 &dbusError.get());1569 if (!reply)1570 halSuccess = false;1571 }1572 1573 /* Parse the reply */1574 if (halSuccess && RT_SUCCESS(rc))1575 {1576 dbus_message_iter_init (reply.get(), &iterGet);1577 if ( dbus_message_iter_get_arg_type (&iterGet) != DBUS_TYPE_ARRAY1578 && dbus_message_iter_get_element_type (&iterGet) != DBUS_TYPE_DICT_ENTRY)1579 halSuccess = false;1580 }1581 if (halSuccess && RT_SUCCESS(rc))1582 dbus_message_iter_recurse (&iterGet, &iterProps);1583 /* Go through all entries in the reply and see if any match our keys. */1584 while ( halSuccess && RT_SUCCESS(rc)1585 && dbus_message_iter_get_arg_type (&iterProps)1586 == DBUS_TYPE_DICT_ENTRY)1587 {1588 const char *pszKey;1589 DBusMessageIter iterEntry, iterValue;1590 dbus_message_iter_recurse (&iterProps, &iterEntry);1591 dbus_message_iter_get_basic (&iterEntry, &pszKey);1592 dbus_message_iter_next (&iterEntry);1593 dbus_message_iter_recurse (&iterEntry, &iterValue);1594 /* Fill in any matches. */1595 for (size_t i = 0; i < cProps; ++i)1596 if (strcmp (pszKey, papszKeys[i]) == 0)1597 {1598 if (dbus_message_iter_get_arg_type (&iterValue) == DBUS_TYPE_STRING)1599 dbus_message_iter_get_basic (&iterValue, &papszValues[i]);1600 }1601 dbus_message_iter_next (&iterProps);1602 }1603 if (RT_SUCCESS(rc) && halSuccess)1604 *pMessage = reply.release();1605 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))1606 rc = VERR_NO_MEMORY;1607 LogFlowFunc (("rc=%Rrc, *pMessage.value()=%p\n", rc, (*pMessage).get()));1608 dbusError.FlowLog();1609 return rc;1610 }1611 1612 /**1613 * Read a set of string properties for a device. If some properties do not1614 * exist or are not of type DBUS_TYPE_STRING, we will still fetch the others.1615 * @returns iprt status code. If the operation failed for non-fatal reasons1616 * then we return success and set *pfSuccess to false.1617 * @param pConnection an initialised connection DBus1618 * @param pszUdi the Udi of the device1619 * @param cProps the number of property values to look up1620 * @param papszKeys the keys of the properties to be looked up1621 * @param pMatches pointer to an empty array of iprt::MiniString to append the1622 * results to. NOT optional.1623 * @param pfMatches pointer to an array of boolean values indicating1624 * whether the respective property is a string. If this1625 * is not supplied then all properties must be strings1626 * for the operation to be considered successful1627 * @param pfSuccess will be set to true if the operation succeeds1628 */1629 /* static */1630 int halGetPropertyStringsVector (DBusConnection *pConnection,1631 const char *pszUdi, size_t cProps,1632 const char **papszKeys,1633 std::vector<iprt::MiniString> *pMatches,1634 bool *pfMatches, bool *pfSuccess)1635 {1636 AssertPtrReturn (pConnection, VERR_INVALID_POINTER);1637 AssertPtrReturn (pszUdi, VERR_INVALID_POINTER);1638 AssertPtrReturn (papszKeys, VERR_INVALID_POINTER);1639 AssertPtrReturn (pMatches, VERR_INVALID_POINTER);1640 AssertReturn((pfMatches == NULL) || VALID_PTR (pfMatches), VERR_INVALID_POINTER);1641 AssertReturn((pfSuccess == NULL) || VALID_PTR (pfSuccess), VERR_INVALID_POINTER);1642 AssertReturn(pMatches->empty(), VERR_INVALID_PARAMETER);1643 LogFlowFunc (("pConnection=%p, pszUdi=%s, cProps=%llu, papszKeys=%p, pMatches=%p, pfMatches=%p, pfSuccess=%p\n",1644 pConnection, pszUdi, cProps, papszKeys, pMatches, pfMatches, pfSuccess));1645 RTMemAutoPtr <char *> values(cProps);1646 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message;1647 bool halSuccess = true;1648 int rc = halGetPropertyStrings (pConnection, pszUdi, cProps, papszKeys,1649 values.get(), &message);1650 if (!message)1651 halSuccess = false;1652 for (size_t i = 0; RT_SUCCESS(rc) && halSuccess && i < cProps; ++i)1653 {1654 bool fMatches = values[i] != NULL;1655 if (pfMatches != NULL)1656 pfMatches[i] = fMatches;1657 else1658 halSuccess = fMatches;1659 try1660 {1661 pMatches->push_back(fMatches ? values[i] : "");1662 }1663 catch(std::bad_alloc &e)1664 {1665 rc = VERR_NO_MEMORY;1666 }1667 }1668 if (pfSuccess != NULL)1669 *pfSuccess = halSuccess;1670 if (RT_SUCCESS(rc) && halSuccess)1671 {1672 Assert(pMatches->size() == cProps);1673 AssertForEach(j, size_t, 0, cProps, (pfMatches == NULL)1674 || (pfMatches[j] == true)1675 || ((pfMatches[j] == false) && (pMatches[j].size() == 0)));1676 }1677 LogFlowFunc (("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));1678 return rc;1679 }1680 1681 1682 /**1683 * Helper function to query the hal subsystem for information about USB devices1684 * attached to the system.1685 * @returns iprt status code1686 * @param pList where to add information about the devices detected1687 * @param pfSuccess will be set to true if all interactions with hal1688 * succeeded and to false otherwise. Optional.1689 *1690 * @returns IPRT status code1691 */1692 /* static */1693 int getUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess)1694 {1695 AssertReturn(VALID_PTR (pList) && (pfSuccess == NULL || VALID_PTR (pfSuccess)),1696 VERR_INVALID_POINTER);1697 LogFlowFunc (("pList=%p, pfSuccess=%p\n", pList, pfSuccess));1698 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */1699 bool halSuccess = true; /* We set this to false to abort the operation. */1700 autoDBusError dbusError;1701 1702 RTMemAutoPtr<DBusMessage, VBoxDBusMessageUnref> message, replyFind, replyGet;1703 RTMemAutoPtr<DBusConnection, VBoxHalShutdown> dbusConnection;1704 DBusMessageIter iterFind, iterUdis;1705 1706 /* Connect to hal */1707 rc = halInit (&dbusConnection);1708 if (!dbusConnection)1709 halSuccess = false;1710 /* Get an array of all devices in the usb_device subsystem */1711 if (halSuccess && RT_SUCCESS(rc))1712 {1713 rc = halFindDeviceStringMatch(dbusConnection.get(), "info.subsystem",1714 "usb_device", &replyFind);1715 if (!replyFind)1716 halSuccess = false;1717 }1718 if (halSuccess && RT_SUCCESS(rc))1719 {1720 dbus_message_iter_init(replyFind.get(), &iterFind);1721 if (dbus_message_iter_get_arg_type (&iterFind) != DBUS_TYPE_ARRAY)1722 halSuccess = false;1723 }1724 /* Recurse down into the array and query interesting information about the1725 * entries. */1726 if (halSuccess && RT_SUCCESS(rc))1727 dbus_message_iter_recurse(&iterFind, &iterUdis);1728 for (; halSuccess && RT_SUCCESS(rc)1729 && dbus_message_iter_get_arg_type(&iterUdis) == DBUS_TYPE_STRING;1730 dbus_message_iter_next(&iterUdis))1731 {1732 /* Get the device node and the sysfs path for the current entry. */1733 const char *pszUdi;1734 dbus_message_iter_get_basic (&iterUdis, &pszUdi);1735 static const char *papszKeys[] = { "linux.device_file", "linux.sysfs_path" };1736 char *papszValues[RT_ELEMENTS(papszKeys)];1737 rc = halGetPropertyStrings(dbusConnection.get(), pszUdi, RT_ELEMENTS(papszKeys),1738 papszKeys, papszValues, &replyGet);1739 const char *pszDevice = papszValues[0], *pszSysfsPath = papszValues[1];1740 /* Get the interfaces. */1741 if (!!replyGet && pszDevice && pszSysfsPath)1742 {1743 USBDeviceInfo info(pszDevice, pszSysfsPath);1744 bool ifaceSuccess = true; /* If we can't get the interfaces, just1745 * skip this one device. */1746 rc = getUSBInterfacesFromHal(&info.mInterfaces, pszUdi, &ifaceSuccess);1747 if (RT_SUCCESS(rc) && halSuccess && ifaceSuccess)1748 try1749 {1750 pList->push_back(info);1751 }1752 catch(std::bad_alloc &e)1753 {1754 rc = VERR_NO_MEMORY;1755 }1756 }1757 }1758 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))1759 rc = VERR_NO_MEMORY;1760 if (pfSuccess != NULL)1761 *pfSuccess = halSuccess;1762 LogFlow(("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));1763 dbusError.FlowLog();1764 return rc;1765 }1766 1767 /**1768 * Helper function to query the hal subsystem for information about USB devices1769 * attached to the system, using the older API.1770 * @returns iprt status code1771 * @param pList where to add information about the devices detected1772 * @param pfSuccess will be set to true if all interactions with hal1773 * succeeded and to false otherwise. Optional.1774 *1775 * @returns IPRT status code1776 */1777 /* static */1778 int getOldUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess)1779 {1780 AssertReturn(VALID_PTR (pList) && (pfSuccess == NULL || VALID_PTR (pfSuccess)),1781 VERR_INVALID_POINTER);1782 LogFlowFunc (("pList=%p, pfSuccess=%p\n", pList, pfSuccess));1783 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */1784 bool halSuccess = true; /* We set this to false to abort the operation. */1785 autoDBusError dbusError;1786 1787 RTMemAutoPtr<DBusMessage, VBoxDBusMessageUnref> message, replyFind, replyGet;1788 RTMemAutoPtr<DBusConnection, VBoxHalShutdown> dbusConnection;1789 DBusMessageIter iterFind, iterUdis;1790 1791 /* Connect to hal */1792 rc = halInit(&dbusConnection);1793 if (!dbusConnection)1794 halSuccess = false;1795 /* Get an array of all devices in the usb_device subsystem */1796 if (halSuccess && RT_SUCCESS(rc))1797 {1798 rc = halFindDeviceStringMatch(dbusConnection.get(), "info.category",1799 "usbraw", &replyFind);1800 if (!replyFind)1801 halSuccess = false;1802 }1803 if (halSuccess && RT_SUCCESS(rc))1804 {1805 dbus_message_iter_init(replyFind.get(), &iterFind);1806 if (dbus_message_iter_get_arg_type(&iterFind) != DBUS_TYPE_ARRAY)1807 halSuccess = false;1808 }1809 /* Recurse down into the array and query interesting information about the1810 * entries. */1811 if (halSuccess && RT_SUCCESS(rc))1812 dbus_message_iter_recurse(&iterFind, &iterUdis);1813 for (; halSuccess && RT_SUCCESS(rc)1814 && dbus_message_iter_get_arg_type(&iterUdis) == DBUS_TYPE_STRING;1815 dbus_message_iter_next(&iterUdis))1816 {1817 /* Get the device node and the sysfs path for the current entry. */1818 const char *pszUdi;1819 dbus_message_iter_get_basic(&iterUdis, &pszUdi);1820 static const char *papszKeys[] = { "linux.device_file", "info.parent" };1821 char *papszValues[RT_ELEMENTS(papszKeys)];1822 rc = halGetPropertyStrings(dbusConnection.get(), pszUdi, RT_ELEMENTS(papszKeys),1823 papszKeys, papszValues, &replyGet);1824 const char *pszDevice = papszValues[0], *pszSysfsPath = papszValues[1];1825 /* Get the interfaces. */1826 if (!!replyGet && pszDevice && pszSysfsPath)1827 {1828 USBDeviceInfo info(pszDevice, pszSysfsPath);1829 bool ifaceSuccess = false; /* If we can't get the interfaces, just1830 * skip this one device. */1831 rc = getUSBInterfacesFromHal(&info.mInterfaces, pszSysfsPath,1832 &ifaceSuccess);1833 if (RT_SUCCESS(rc) && halSuccess && ifaceSuccess)1834 try1835 {1836 pList->push_back(info);1837 }1838 catch(std::bad_alloc &e)1839 {1840 rc = VERR_NO_MEMORY;1841 }1842 }1843 }1844 if (dbusError.HasName(DBUS_ERROR_NO_MEMORY))1845 rc = VERR_NO_MEMORY;1846 if (pfSuccess != NULL)1847 *pfSuccess = halSuccess;1848 LogFlow(("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));1849 dbusError.FlowLog();1850 return rc;1851 }1852 1853 1159 class sysfsPathHandler 1854 1160 { … … 2020 1326 } 2021 1327 }; 1328 1329 /** 1330 * Helper function to query the sysfs subsystem for information about USB 1331 * devices attached to the system. 1332 * @returns iprt status code 1333 * @param pList where to add information about the drives detected 1334 * @param pfSuccess Did we find anything? 1335 * 1336 * @returns IPRT status code 1337 */ 1338 static int getUSBDeviceInfoFromSysfs(USBDeviceInfoList *pList, 1339 bool *pfSuccess) 1340 { 1341 AssertPtrReturn(pList, VERR_INVALID_POINTER); 1342 AssertPtrNullReturn(pfSuccess, VERR_INVALID_POINTER); /* Valid or Null */ 1343 LogFlowFunc (("pList=%p, pfSuccess=%p\n", 1344 pList, pfSuccess)); 1345 size_t cDevices = pList->size(); 1346 matchUSBDevice devHandler(pList); 1347 int rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", &devHandler); 1348 do { 1349 if (RT_FAILURE(rc)) 1350 break; 1351 for (USBDeviceInfoList::iterator pInfo = pList->begin(); 1352 pInfo != pList->end(); ++pInfo) 1353 { 1354 matchUSBInterface ifaceHandler(&*pInfo); 1355 rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", &ifaceHandler); 1356 if (RT_FAILURE(rc)) 1357 break; 1358 } 1359 } while(0); 1360 if (RT_FAILURE(rc)) 1361 /* Clean up again */ 1362 while (pList->size() > cDevices) 1363 pList->pop_back(); 1364 if (pfSuccess) 1365 *pfSuccess = RT_SUCCESS(rc); 1366 LogFlow (("rc=%Rrc\n", rc)); 1367 return rc; 1368 } 1369 1370 1371 #if defined(RT_OS_LINUX) && defined(VBOX_WITH_DBUS) 1372 /** Wrapper class around DBusError for automatic cleanup */ 1373 class autoDBusError 1374 { 1375 DBusError mError; 1376 public: 1377 autoDBusError () { dbus_error_init (&mError); } 1378 ~autoDBusError () 1379 { 1380 if (IsSet()) 1381 dbus_error_free (&mError); 1382 } 1383 DBusError &get () { return mError; } 1384 bool IsSet () 1385 { 1386 Assert((mError.name == NULL) == (mError.message == NULL)); 1387 return (mError.name != NULL); 1388 } 1389 bool HasName (const char *pcszName) 1390 { 1391 Assert((mError.name == NULL) == (mError.message == NULL)); 1392 return (RTStrCmp (mError.name, pcszName) == 0); 1393 } 1394 void FlowLog () 1395 { 1396 if (IsSet ()) 1397 LogFlow(("DBus error %s: %s\n", mError.name, mError.message)); 1398 } 1399 }; 1400 1401 /** 1402 * Helper function for setting up a connection to the DBus daemon and 1403 * registering with the hal service. 1404 * 1405 * @note If libdbus is being loaded at runtime then be sure to call 1406 * VBoxDBusCheckPresence before calling this. 1407 * @returns iprt status code 1408 * @param ppConnection where to store the connection handle 1409 */ 1410 /* static */ 1411 int halInit (RTMemAutoPtr <DBusConnection, VBoxHalShutdown> *pConnection) 1412 { 1413 AssertReturn(VALID_PTR (pConnection), VERR_INVALID_POINTER); 1414 LogFlowFunc (("pConnection=%p\n", pConnection)); 1415 int rc = VINF_SUCCESS; 1416 bool halSuccess = true; 1417 autoDBusError dbusError; 1418 1419 RTMemAutoPtr <DBusConnection, VBoxDBusConnectionUnref> dbusConnection; 1420 dbusConnection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbusError.get()); 1421 if (!dbusConnection) 1422 halSuccess = false; 1423 if (halSuccess) 1424 { 1425 dbus_connection_set_exit_on_disconnect (dbusConnection.get(), false); 1426 halSuccess = dbus_bus_name_has_owner (dbusConnection.get(), 1427 "org.freedesktop.Hal", &dbusError.get()); 1428 } 1429 if (halSuccess) 1430 { 1431 dbus_bus_add_match (dbusConnection.get(), 1432 "type='signal'," 1433 "interface='org.freedesktop.Hal.Manager'," 1434 "sender='org.freedesktop.Hal'," 1435 "path='/org/freedesktop/Hal/Manager'", 1436 &dbusError.get()); 1437 halSuccess = !dbusError.IsSet(); 1438 } 1439 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY)) 1440 rc = VERR_NO_MEMORY; 1441 if (halSuccess) 1442 *pConnection = dbusConnection.release(); 1443 LogFlowFunc(("rc=%Rrc, (*pConnection).get()=%p\n", rc, (*pConnection).get())); 1444 dbusError.FlowLog(); 1445 return rc; 1446 } 1447 1448 /** 1449 * Helper function for setting up a private connection to the DBus daemon and 1450 * registering with the hal service. Private connections are considered 1451 * unsociable and should not be used unnecessarily (as per the DBus API docs). 1452 * 1453 * @note If libdbus is being loaded at runtime then be sure to call 1454 * VBoxDBusCheckPresence before calling this. 1455 * @returns iprt status code 1456 * @param pConnection where to store the connection handle 1457 */ 1458 /* static */ 1459 int halInitPrivate (RTMemAutoPtr <DBusConnection, VBoxHalShutdownPrivate> *pConnection) 1460 { 1461 AssertReturn(VALID_PTR (pConnection), VERR_INVALID_POINTER); 1462 LogFlowFunc (("pConnection=%p\n", pConnection)); 1463 int rc = VINF_SUCCESS; 1464 bool halSuccess = true; 1465 autoDBusError dbusError; 1466 1467 RTMemAutoPtr <DBusConnection, VBoxDBusConnectionCloseAndUnref> dbusConnection; 1468 dbusConnection = dbus_bus_get_private (DBUS_BUS_SYSTEM, &dbusError.get()); 1469 if (!dbusConnection) 1470 halSuccess = false; 1471 if (halSuccess) 1472 { 1473 dbus_connection_set_exit_on_disconnect (dbusConnection.get(), false); 1474 halSuccess = dbus_bus_name_has_owner (dbusConnection.get(), 1475 "org.freedesktop.Hal", &dbusError.get()); 1476 } 1477 if (halSuccess) 1478 { 1479 dbus_bus_add_match (dbusConnection.get(), 1480 "type='signal'," 1481 "interface='org.freedesktop.Hal.Manager'," 1482 "sender='org.freedesktop.Hal'," 1483 "path='/org/freedesktop/Hal/Manager'", 1484 &dbusError.get()); 1485 halSuccess = !dbusError.IsSet(); 1486 } 1487 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY)) 1488 rc = VERR_NO_MEMORY; 1489 if (halSuccess) 1490 *pConnection = dbusConnection.release(); 1491 LogFlowFunc(("rc=%Rrc, (*pConnection).get()=%p\n", rc, (*pConnection).get())); 1492 dbusError.FlowLog(); 1493 return rc; 1494 } 1495 1496 /** 1497 * Helper function for shutting down a connection to DBus and hal. 1498 * @param pConnection the connection handle 1499 */ 1500 /* extern */ 1501 void VBoxHalShutdown (DBusConnection *pConnection) 1502 { 1503 AssertReturnVoid(VALID_PTR (pConnection)); 1504 LogFlowFunc (("pConnection=%p\n", pConnection)); 1505 autoDBusError dbusError; 1506 1507 dbus_bus_remove_match (pConnection, 1508 "type='signal'," 1509 "interface='org.freedesktop.Hal.Manager'," 1510 "sender='org.freedesktop.Hal'," 1511 "path='/org/freedesktop/Hal/Manager'", 1512 &dbusError.get()); 1513 dbus_connection_unref (pConnection); 1514 LogFlowFunc(("returning\n")); 1515 dbusError.FlowLog(); 1516 } 1517 1518 /** 1519 * Helper function for shutting down a private connection to DBus and hal. 1520 * @param pConnection the connection handle 1521 */ 1522 /* extern */ 1523 void VBoxHalShutdownPrivate (DBusConnection *pConnection) 1524 { 1525 AssertReturnVoid(VALID_PTR (pConnection)); 1526 LogFlowFunc (("pConnection=%p\n", pConnection)); 1527 autoDBusError dbusError; 1528 1529 dbus_bus_remove_match (pConnection, 1530 "type='signal'," 1531 "interface='org.freedesktop.Hal.Manager'," 1532 "sender='org.freedesktop.Hal'," 1533 "path='/org/freedesktop/Hal/Manager'", 1534 &dbusError.get()); 1535 dbus_connection_close (pConnection); 1536 dbus_connection_unref (pConnection); 1537 LogFlowFunc(("returning\n")); 1538 dbusError.FlowLog(); 1539 } 1540 1541 /** Wrapper around dbus_connection_unref. We need this to use it as a real 1542 * function in auto pointers, as a function pointer won't wash here. */ 1543 /* extern */ 1544 void VBoxDBusConnectionUnref(DBusConnection *pConnection) 1545 { 1546 dbus_connection_unref(pConnection); 1547 } 1548 1549 /** 1550 * This function closes and unrefs a private connection to dbus. It should 1551 * only be called once no-one else is referencing the connection. 1552 */ 1553 /* extern */ 1554 void VBoxDBusConnectionCloseAndUnref(DBusConnection *pConnection) 1555 { 1556 dbus_connection_close(pConnection); 1557 dbus_connection_unref(pConnection); 1558 } 1559 1560 /** Wrapper around dbus_message_unref. We need this to use it as a real 1561 * function in auto pointers, as a function pointer won't wash here. */ 1562 /* extern */ 1563 void VBoxDBusMessageUnref(DBusMessage *pMessage) 1564 { 1565 dbus_message_unref(pMessage); 1566 } 1567 1568 /** 1569 * Find the UDIs of hal entries that contain Key=Value property. 1570 * @returns iprt status code. If a non-fatal error occurs, we return success 1571 * but reset pMessage to NULL. 1572 * @param pConnection an initialised connection DBus 1573 * @param pszKey the property key 1574 * @param pszValue the property value 1575 * @param pMessage where to store the return DBus message. This must be 1576 * parsed to get at the UDIs. NOT optional. 1577 */ 1578 /* static */ 1579 int halFindDeviceStringMatch (DBusConnection *pConnection, const char *pszKey, 1580 const char *pszValue, 1581 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage) 1582 { 1583 AssertReturn( VALID_PTR (pConnection) && VALID_PTR (pszKey) 1584 && VALID_PTR (pszValue) && VALID_PTR (pMessage), 1585 VERR_INVALID_POINTER); 1586 LogFlowFunc (("pConnection=%p, pszKey=%s, pszValue=%s, pMessage=%p\n", 1587 pConnection, pszKey, pszValue, pMessage)); 1588 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */ 1589 bool halSuccess = true; /* We set this to false to abort the operation. */ 1590 autoDBusError dbusError; 1591 1592 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, reply; 1593 if (halSuccess && RT_SUCCESS(rc)) 1594 { 1595 message = dbus_message_new_method_call ("org.freedesktop.Hal", 1596 "/org/freedesktop/Hal/Manager", 1597 "org.freedesktop.Hal.Manager", 1598 "FindDeviceStringMatch"); 1599 if (!message) 1600 rc = VERR_NO_MEMORY; 1601 } 1602 if (halSuccess && RT_SUCCESS(rc)) 1603 { 1604 DBusMessageIter iterAppend; 1605 dbus_message_iter_init_append (message.get(), &iterAppend); 1606 dbus_message_iter_append_basic (&iterAppend, DBUS_TYPE_STRING, &pszKey); 1607 dbus_message_iter_append_basic (&iterAppend, DBUS_TYPE_STRING, &pszValue); 1608 reply = dbus_connection_send_with_reply_and_block (pConnection, 1609 message.get(), -1, 1610 &dbusError.get()); 1611 if (!reply) 1612 halSuccess = false; 1613 } 1614 *pMessage = reply.release (); 1615 LogFlowFunc (("rc=%Rrc, *pMessage.value()=%p\n", rc, (*pMessage).get())); 1616 dbusError.FlowLog(); 1617 return rc; 1618 } 1619 1620 /** 1621 * Find the UDIs of hal entries that contain Key=Value property and return the 1622 * result on the end of a vector of iprt::MiniString. 1623 * @returns iprt status code. If a non-fatal error occurs, we return success 1624 * but set *pfSuccess to false. 1625 * @param pConnection an initialised connection DBus 1626 * @param pszKey the property key 1627 * @param pszValue the property value 1628 * @param pMatches pointer to an array of iprt::MiniString to append the 1629 * results to. NOT optional. 1630 * @param pfSuccess will be set to true if the operation succeeds 1631 */ 1632 /* static */ 1633 int halFindDeviceStringMatchVector (DBusConnection *pConnection, 1634 const char *pszKey, const char *pszValue, 1635 std::vector<iprt::MiniString> *pMatches, 1636 bool *pfSuccess) 1637 { 1638 AssertPtrReturn (pConnection, VERR_INVALID_POINTER); 1639 AssertPtrReturn (pszKey, VERR_INVALID_POINTER); 1640 AssertPtrReturn (pszValue, VERR_INVALID_POINTER); 1641 AssertPtrReturn (pMatches, VERR_INVALID_POINTER); 1642 AssertReturn(pfSuccess == NULL || VALID_PTR (pfSuccess), VERR_INVALID_POINTER); 1643 LogFlowFunc (("pConnection=%p, pszKey=%s, pszValue=%s, pMatches=%p, pfSuccess=%p\n", 1644 pConnection, pszKey, pszValue, pMatches, pfSuccess)); 1645 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */ 1646 bool halSuccess = true; /* We set this to false to abort the operation. */ 1647 1648 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, replyFind; 1649 DBusMessageIter iterFind, iterUdis; 1650 1651 if (halSuccess && RT_SUCCESS(rc)) 1652 { 1653 rc = halFindDeviceStringMatch (pConnection, pszKey, pszValue, 1654 &replyFind); 1655 if (!replyFind) 1656 halSuccess = false; 1657 } 1658 if (halSuccess && RT_SUCCESS(rc)) 1659 { 1660 dbus_message_iter_init (replyFind.get(), &iterFind); 1661 if (dbus_message_iter_get_arg_type (&iterFind) != DBUS_TYPE_ARRAY) 1662 halSuccess = false; 1663 } 1664 if (halSuccess && RT_SUCCESS(rc)) 1665 dbus_message_iter_recurse (&iterFind, &iterUdis); 1666 for (; halSuccess && RT_SUCCESS(rc) 1667 && dbus_message_iter_get_arg_type (&iterUdis) == DBUS_TYPE_STRING; 1668 dbus_message_iter_next(&iterUdis)) 1669 { 1670 /* Now get all UDIs from the iterator */ 1671 const char *pszUdi; 1672 dbus_message_iter_get_basic (&iterUdis, &pszUdi); 1673 try 1674 { 1675 pMatches->push_back(pszUdi); 1676 } 1677 catch(std::bad_alloc &e) 1678 { 1679 rc = VERR_NO_MEMORY; 1680 } 1681 } 1682 if (pfSuccess != NULL) 1683 *pfSuccess = halSuccess; 1684 LogFlow (("rc=%Rrc, halSuccess=%d\n", rc, halSuccess)); 1685 return rc; 1686 } 1687 1688 /** 1689 * Read a set of string properties for a device. If some of the properties are 1690 * not of type DBUS_TYPE_STRING or do not exist then a NULL pointer will be 1691 * returned for them. 1692 * @returns iprt status code. If the operation failed for non-fatal reasons 1693 * then we return success and leave pMessage untouched - reset it 1694 * before the call to detect this. 1695 * @param pConnection an initialised connection DBus 1696 * @param pszUdi the Udi of the device 1697 * @param cProps the number of property values to look up 1698 * @param papszKeys the keys of the properties to be looked up 1699 * @param papszValues where to store the values of the properties. The 1700 * strings returned will be valid until the message 1701 * returned in @a ppMessage is freed. Undefined if 1702 * the message is NULL. 1703 * @param pMessage where to store the return DBus message. The caller 1704 * is responsible for freeing this once they have 1705 * finished with the value strings. NOT optional. 1706 */ 1707 /* static */ 1708 int halGetPropertyStrings (DBusConnection *pConnection, const char *pszUdi, 1709 size_t cProps, const char **papszKeys, 1710 char **papszValues, 1711 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage) 1712 { 1713 AssertReturn( VALID_PTR (pConnection) && VALID_PTR (pszUdi) 1714 && VALID_PTR (papszKeys) && VALID_PTR (papszValues) 1715 && VALID_PTR (pMessage), 1716 VERR_INVALID_POINTER); 1717 LogFlowFunc (("pConnection=%p, pszUdi=%s, cProps=%llu, papszKeys=%p, papszValues=%p, pMessage=%p\n", 1718 pConnection, pszUdi, cProps, papszKeys, papszValues, pMessage)); 1719 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */ 1720 bool halSuccess = true; /* We set this to false to abort the operation. */ 1721 autoDBusError dbusError; 1722 1723 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, reply; 1724 DBusMessageIter iterGet, iterProps; 1725 1726 /* Initialise the return array to NULLs */ 1727 for (size_t i = 0; i < cProps; ++i) 1728 papszValues[i] = NULL; 1729 1730 /* Send a GetAllProperties message to hald */ 1731 message = dbus_message_new_method_call ("org.freedesktop.Hal", pszUdi, 1732 "org.freedesktop.Hal.Device", 1733 "GetAllProperties"); 1734 if (!message) 1735 rc = VERR_NO_MEMORY; 1736 if (halSuccess && RT_SUCCESS(rc)) 1737 { 1738 reply = dbus_connection_send_with_reply_and_block (pConnection, 1739 message.get(), -1, 1740 &dbusError.get()); 1741 if (!reply) 1742 halSuccess = false; 1743 } 1744 1745 /* Parse the reply */ 1746 if (halSuccess && RT_SUCCESS(rc)) 1747 { 1748 dbus_message_iter_init (reply.get(), &iterGet); 1749 if ( dbus_message_iter_get_arg_type (&iterGet) != DBUS_TYPE_ARRAY 1750 && dbus_message_iter_get_element_type (&iterGet) != DBUS_TYPE_DICT_ENTRY) 1751 halSuccess = false; 1752 } 1753 if (halSuccess && RT_SUCCESS(rc)) 1754 dbus_message_iter_recurse (&iterGet, &iterProps); 1755 /* Go through all entries in the reply and see if any match our keys. */ 1756 while ( halSuccess && RT_SUCCESS(rc) 1757 && dbus_message_iter_get_arg_type (&iterProps) 1758 == DBUS_TYPE_DICT_ENTRY) 1759 { 1760 const char *pszKey; 1761 DBusMessageIter iterEntry, iterValue; 1762 dbus_message_iter_recurse (&iterProps, &iterEntry); 1763 dbus_message_iter_get_basic (&iterEntry, &pszKey); 1764 dbus_message_iter_next (&iterEntry); 1765 dbus_message_iter_recurse (&iterEntry, &iterValue); 1766 /* Fill in any matches. */ 1767 for (size_t i = 0; i < cProps; ++i) 1768 if (strcmp (pszKey, papszKeys[i]) == 0) 1769 { 1770 if (dbus_message_iter_get_arg_type (&iterValue) == DBUS_TYPE_STRING) 1771 dbus_message_iter_get_basic (&iterValue, &papszValues[i]); 1772 } 1773 dbus_message_iter_next (&iterProps); 1774 } 1775 if (RT_SUCCESS(rc) && halSuccess) 1776 *pMessage = reply.release(); 1777 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY)) 1778 rc = VERR_NO_MEMORY; 1779 LogFlowFunc (("rc=%Rrc, *pMessage.value()=%p\n", rc, (*pMessage).get())); 1780 dbusError.FlowLog(); 1781 return rc; 1782 } 1783 1784 /** 1785 * Read a set of string properties for a device. If some properties do not 1786 * exist or are not of type DBUS_TYPE_STRING, we will still fetch the others. 1787 * @returns iprt status code. If the operation failed for non-fatal reasons 1788 * then we return success and set *pfSuccess to false. 1789 * @param pConnection an initialised connection DBus 1790 * @param pszUdi the Udi of the device 1791 * @param cProps the number of property values to look up 1792 * @param papszKeys the keys of the properties to be looked up 1793 * @param pMatches pointer to an empty array of iprt::MiniString to append the 1794 * results to. NOT optional. 1795 * @param pfMatches pointer to an array of boolean values indicating 1796 * whether the respective property is a string. If this 1797 * is not supplied then all properties must be strings 1798 * for the operation to be considered successful 1799 * @param pfSuccess will be set to true if the operation succeeds 1800 */ 1801 /* static */ 1802 int halGetPropertyStringsVector (DBusConnection *pConnection, 1803 const char *pszUdi, size_t cProps, 1804 const char **papszKeys, 1805 std::vector<iprt::MiniString> *pMatches, 1806 bool *pfMatches, bool *pfSuccess) 1807 { 1808 AssertPtrReturn (pConnection, VERR_INVALID_POINTER); 1809 AssertPtrReturn (pszUdi, VERR_INVALID_POINTER); 1810 AssertPtrReturn (papszKeys, VERR_INVALID_POINTER); 1811 AssertPtrReturn (pMatches, VERR_INVALID_POINTER); 1812 AssertReturn((pfMatches == NULL) || VALID_PTR (pfMatches), VERR_INVALID_POINTER); 1813 AssertReturn((pfSuccess == NULL) || VALID_PTR (pfSuccess), VERR_INVALID_POINTER); 1814 AssertReturn(pMatches->empty(), VERR_INVALID_PARAMETER); 1815 LogFlowFunc (("pConnection=%p, pszUdi=%s, cProps=%llu, papszKeys=%p, pMatches=%p, pfMatches=%p, pfSuccess=%p\n", 1816 pConnection, pszUdi, cProps, papszKeys, pMatches, pfMatches, pfSuccess)); 1817 RTMemAutoPtr <char *> values(cProps); 1818 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message; 1819 bool halSuccess = true; 1820 int rc = halGetPropertyStrings (pConnection, pszUdi, cProps, papszKeys, 1821 values.get(), &message); 1822 if (!message) 1823 halSuccess = false; 1824 for (size_t i = 0; RT_SUCCESS(rc) && halSuccess && i < cProps; ++i) 1825 { 1826 bool fMatches = values[i] != NULL; 1827 if (pfMatches != NULL) 1828 pfMatches[i] = fMatches; 1829 else 1830 halSuccess = fMatches; 1831 try 1832 { 1833 pMatches->push_back(fMatches ? values[i] : ""); 1834 } 1835 catch(std::bad_alloc &e) 1836 { 1837 rc = VERR_NO_MEMORY; 1838 } 1839 } 1840 if (pfSuccess != NULL) 1841 *pfSuccess = halSuccess; 1842 if (RT_SUCCESS(rc) && halSuccess) 1843 { 1844 Assert(pMatches->size() == cProps); 1845 AssertForEach(j, size_t, 0, cProps, (pfMatches == NULL) 1846 || (pfMatches[j] == true) 1847 || ((pfMatches[j] == false) && (pMatches[j].size() == 0))); 1848 } 1849 LogFlowFunc (("rc=%Rrc, halSuccess=%d\n", rc, halSuccess)); 1850 return rc; 1851 } 1852 1853 1854 /** 1855 * Helper function to query the hal subsystem for information about USB devices 1856 * attached to the system. 1857 * @returns iprt status code 1858 * @param pList where to add information about the devices detected 1859 * @param pfSuccess will be set to true if all interactions with hal 1860 * succeeded and to false otherwise. Optional. 1861 * 1862 * @returns IPRT status code 1863 */ 1864 /* static */ 1865 int getUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess) 1866 { 1867 AssertReturn(VALID_PTR (pList) && (pfSuccess == NULL || VALID_PTR (pfSuccess)), 1868 VERR_INVALID_POINTER); 1869 LogFlowFunc (("pList=%p, pfSuccess=%p\n", pList, pfSuccess)); 1870 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */ 1871 bool halSuccess = true; /* We set this to false to abort the operation. */ 1872 autoDBusError dbusError; 1873 1874 RTMemAutoPtr<DBusMessage, VBoxDBusMessageUnref> message, replyFind, replyGet; 1875 RTMemAutoPtr<DBusConnection, VBoxHalShutdown> dbusConnection; 1876 DBusMessageIter iterFind, iterUdis; 1877 1878 /* Connect to hal */ 1879 rc = halInit (&dbusConnection); 1880 if (!dbusConnection) 1881 halSuccess = false; 1882 /* Get an array of all devices in the usb_device subsystem */ 1883 if (halSuccess && RT_SUCCESS(rc)) 1884 { 1885 rc = halFindDeviceStringMatch(dbusConnection.get(), "info.subsystem", 1886 "usb_device", &replyFind); 1887 if (!replyFind) 1888 halSuccess = false; 1889 } 1890 if (halSuccess && RT_SUCCESS(rc)) 1891 { 1892 dbus_message_iter_init(replyFind.get(), &iterFind); 1893 if (dbus_message_iter_get_arg_type (&iterFind) != DBUS_TYPE_ARRAY) 1894 halSuccess = false; 1895 } 1896 /* Recurse down into the array and query interesting information about the 1897 * entries. */ 1898 if (halSuccess && RT_SUCCESS(rc)) 1899 dbus_message_iter_recurse(&iterFind, &iterUdis); 1900 for (; halSuccess && RT_SUCCESS(rc) 1901 && dbus_message_iter_get_arg_type(&iterUdis) == DBUS_TYPE_STRING; 1902 dbus_message_iter_next(&iterUdis)) 1903 { 1904 /* Get the device node and the sysfs path for the current entry. */ 1905 const char *pszUdi; 1906 dbus_message_iter_get_basic (&iterUdis, &pszUdi); 1907 static const char *papszKeys[] = { "linux.device_file", "linux.sysfs_path" }; 1908 char *papszValues[RT_ELEMENTS(papszKeys)]; 1909 rc = halGetPropertyStrings(dbusConnection.get(), pszUdi, RT_ELEMENTS(papszKeys), 1910 papszKeys, papszValues, &replyGet); 1911 const char *pszDevice = papszValues[0], *pszSysfsPath = papszValues[1]; 1912 /* Get the interfaces. */ 1913 if (!!replyGet && pszDevice && pszSysfsPath) 1914 { 1915 USBDeviceInfo info(pszDevice, pszSysfsPath); 1916 bool ifaceSuccess = true; /* If we can't get the interfaces, just 1917 * skip this one device. */ 1918 rc = getUSBInterfacesFromHal(&info.mInterfaces, pszUdi, &ifaceSuccess); 1919 if (RT_SUCCESS(rc) && halSuccess && ifaceSuccess) 1920 try 1921 { 1922 pList->push_back(info); 1923 } 1924 catch(std::bad_alloc &e) 1925 { 1926 rc = VERR_NO_MEMORY; 1927 } 1928 } 1929 } 1930 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY)) 1931 rc = VERR_NO_MEMORY; 1932 if (pfSuccess != NULL) 1933 *pfSuccess = halSuccess; 1934 LogFlow(("rc=%Rrc, halSuccess=%d\n", rc, halSuccess)); 1935 dbusError.FlowLog(); 1936 return rc; 1937 } 1938 1939 /** 1940 * Helper function to query the hal subsystem for information about USB devices 1941 * attached to the system, using the older API. 1942 * @returns iprt status code 1943 * @param pList where to add information about the devices detected 1944 * @param pfSuccess will be set to true if all interactions with hal 1945 * succeeded and to false otherwise. Optional. 1946 * 1947 * @returns IPRT status code 1948 */ 1949 /* static */ 1950 int getOldUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess) 1951 { 1952 AssertReturn(VALID_PTR (pList) && (pfSuccess == NULL || VALID_PTR (pfSuccess)), 1953 VERR_INVALID_POINTER); 1954 LogFlowFunc (("pList=%p, pfSuccess=%p\n", pList, pfSuccess)); 1955 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */ 1956 bool halSuccess = true; /* We set this to false to abort the operation. */ 1957 autoDBusError dbusError; 1958 1959 RTMemAutoPtr<DBusMessage, VBoxDBusMessageUnref> message, replyFind, replyGet; 1960 RTMemAutoPtr<DBusConnection, VBoxHalShutdown> dbusConnection; 1961 DBusMessageIter iterFind, iterUdis; 1962 1963 /* Connect to hal */ 1964 rc = halInit(&dbusConnection); 1965 if (!dbusConnection) 1966 halSuccess = false; 1967 /* Get an array of all devices in the usb_device subsystem */ 1968 if (halSuccess && RT_SUCCESS(rc)) 1969 { 1970 rc = halFindDeviceStringMatch(dbusConnection.get(), "info.category", 1971 "usbraw", &replyFind); 1972 if (!replyFind) 1973 halSuccess = false; 1974 } 1975 if (halSuccess && RT_SUCCESS(rc)) 1976 { 1977 dbus_message_iter_init(replyFind.get(), &iterFind); 1978 if (dbus_message_iter_get_arg_type(&iterFind) != DBUS_TYPE_ARRAY) 1979 halSuccess = false; 1980 } 1981 /* Recurse down into the array and query interesting information about the 1982 * entries. */ 1983 if (halSuccess && RT_SUCCESS(rc)) 1984 dbus_message_iter_recurse(&iterFind, &iterUdis); 1985 for (; halSuccess && RT_SUCCESS(rc) 1986 && dbus_message_iter_get_arg_type(&iterUdis) == DBUS_TYPE_STRING; 1987 dbus_message_iter_next(&iterUdis)) 1988 { 1989 /* Get the device node and the sysfs path for the current entry. */ 1990 const char *pszUdi; 1991 dbus_message_iter_get_basic(&iterUdis, &pszUdi); 1992 static const char *papszKeys[] = { "linux.device_file", "info.parent" }; 1993 char *papszValues[RT_ELEMENTS(papszKeys)]; 1994 rc = halGetPropertyStrings(dbusConnection.get(), pszUdi, RT_ELEMENTS(papszKeys), 1995 papszKeys, papszValues, &replyGet); 1996 const char *pszDevice = papszValues[0], *pszSysfsPath = papszValues[1]; 1997 /* Get the interfaces. */ 1998 if (!!replyGet && pszDevice && pszSysfsPath) 1999 { 2000 USBDeviceInfo info(pszDevice, pszSysfsPath); 2001 bool ifaceSuccess = false; /* If we can't get the interfaces, just 2002 * skip this one device. */ 2003 rc = getUSBInterfacesFromHal(&info.mInterfaces, pszSysfsPath, 2004 &ifaceSuccess); 2005 if (RT_SUCCESS(rc) && halSuccess && ifaceSuccess) 2006 try 2007 { 2008 pList->push_back(info); 2009 } 2010 catch(std::bad_alloc &e) 2011 { 2012 rc = VERR_NO_MEMORY; 2013 } 2014 } 2015 } 2016 if (dbusError.HasName(DBUS_ERROR_NO_MEMORY)) 2017 rc = VERR_NO_MEMORY; 2018 if (pfSuccess != NULL) 2019 *pfSuccess = halSuccess; 2020 LogFlow(("rc=%Rrc, halSuccess=%d\n", rc, halSuccess)); 2021 dbusError.FlowLog(); 2022 return rc; 2023 } 2024 2022 2025 2023 2026 /**
Note:
See TracChangeset
for help on using the changeset viewer.