Changeset 31564 in vbox for trunk/src/VBox/Main
- Timestamp:
- Aug 11, 2010 12:42:43 PM (14 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/linux/HostHardwareLinux.cpp
r30659 r31564 29 29 #include <VBox/log.h> 30 30 31 #ifdef VBOX_USB_WITH_DBUS32 # include <VBox/dbus.h>33 #endif34 35 31 #include <iprt/asm.h> 36 32 #include <iprt/dir.h> … … 83 79 ******************************************************************************/ 84 80 85 /** When waiting for hotplug events, we currently restart the wait after at86 * most this many milliseconds. */87 enum { DBUS_POLL_TIMEOUT = 2000 /* ms */ };88 89 81 static int getDriveInfoFromEnv(const char *pcszVar, DriveInfoList *pList, 90 82 bool isDVD, bool *pfSuccess); … … 116 108 static int getDeviceInfoFromSysfs(const char *pcszPath, pathHandler *pHandler); 117 109 # endif 118 # ifdef VBOX_USB_WITH_DBUS119 /* These must be extern to be usable in the RTMemAutoPtr template */120 extern void VBoxHalShutdown (DBusConnection *pConnection);121 extern void VBoxHalShutdownPrivate (DBusConnection *pConnection);122 extern void VBoxDBusConnectionUnref(DBusConnection *pConnection);123 extern void VBoxDBusConnectionCloseAndUnref(DBusConnection *pConnection);124 extern void VBoxDBusMessageUnref(DBusMessage *pMessage);125 126 static int halInit(RTMemAutoPtr <DBusConnection, VBoxHalShutdown> *pConnection);127 static int halInitPrivate(RTMemAutoPtr <DBusConnection, VBoxHalShutdownPrivate> *pConnection);128 static int halFindDeviceStringMatch (DBusConnection *pConnection,129 const char *pszKey, const char *pszValue,130 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage);131 /*132 static int halFindDeviceStringMatchVector (DBusConnection *pConnection,133 const char *pszKey,134 const char *pszValue,135 std::vector<iprt::MiniString> *pMatches);136 */137 static int halGetPropertyStrings (DBusConnection *pConnection,138 const char *pszUdi, size_t cKeys,139 const char **papszKeys, char **papszValues,140 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage);141 /*142 static int halGetPropertyStringsVector (DBusConnection *pConnection,143 const char *pszUdi, size_t cProps,144 const char **papszKeys,145 std::vector<iprt::MiniString> *pMatches,146 bool *pfMatches, bool *pfSuccess);147 */148 static int getUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess);149 static int getOldUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess);150 static int getUSBInterfacesFromHal(std::vector <iprt::MiniString> *pList,151 const char *pcszUdi, bool *pfSuccess);152 static DBusHandlerResult dbusFilterFunction (DBusConnection *pConnection,153 DBusMessage *pMessage, void *pvUser);154 # endif /* VBOX_USB_WITH_DBUS */155 110 #endif /* VBOX_USB_WITH_SYSFS */ 156 111 … … 1047 1002 mDeviceList.clear(); 1048 1003 #ifdef VBOX_USB_WITH_SYSFS 1049 # ifdef VBOX_USB_WITH_DBUS1050 bool halSuccess = false;1051 if ( RT_SUCCESS(rc)1052 && RT_SUCCESS(RTDBusLoadLib())1053 && (!success || testing()))1054 rc = getUSBDeviceInfoFromHal(&mDeviceList, &halSuccess);1055 /* Try the old API if the new one *succeeded* as only one of them will1056 * pick up devices anyway. */1057 if (RT_SUCCESS(rc) && halSuccess && (!success || testing()))1058 rc = getOldUSBDeviceInfoFromHal(&mDeviceList, &halSuccess);1059 if (!success)1060 success = halSuccess;1061 # endif /* VBOX_USB_WITH_DBUS */1062 1004 # ifdef VBOX_USB_WITH_INOTIFY 1063 1005 if ( RT_SUCCESS(rc) … … 1076 1018 return rc; 1077 1019 } 1078 1079 #if defined VBOX_USB_WITH_SYSFS && defined VBOX_USB_WITH_DBUS1080 class hotplugDBusImpl : public VBoxMainHotplugWaiterImpl1081 {1082 /** The connection to DBus */1083 RTMemAutoPtr <DBusConnection, VBoxHalShutdownPrivate> mConnection;1084 /** Semaphore which is set when a device is hotplugged and reset when1085 * it is read. */1086 volatile bool mTriggered;1087 /** A flag to say that we wish to interrupt the current wait. */1088 volatile bool mInterrupt;1089 /** The constructor "return code" */1090 int mStatus;1091 1092 public:1093 /** Test whether this implementation can be used on the current system */1094 static bool Available(void)1095 {1096 RTMemAutoPtr<DBusConnection, VBoxHalShutdown> dbusConnection;1097 1098 /* Try to open a test connection to hal */1099 if (RT_SUCCESS(RTDBusLoadLib()) && RT_SUCCESS(halInit (&dbusConnection)))1100 return !!dbusConnection;1101 return false;1102 }1103 1104 /** Constructor */1105 hotplugDBusImpl (void);1106 virtual ~hotplugDBusImpl (void);1107 /** @copydoc VBoxMainHotplugWaiter::Wait */1108 virtual int Wait (RTMSINTERVAL cMillies);1109 /** @copydoc VBoxMainHotplugWaiter::Interrupt */1110 virtual void Interrupt (void);1111 /** @copydoc VBoxMainHotplugWaiter::getStatus */1112 virtual int getStatus(void)1113 {1114 return mStatus;1115 }1116 };1117 1118 /* This constructor sets up a private connection to the DBus daemon, connects1119 * to the hal service and installs a filter which sets the mTriggered flag in1120 * the Context structure when a device (not necessarily USB) is added or1121 * removed. */1122 hotplugDBusImpl::hotplugDBusImpl (void) : mTriggered(false), mInterrupt(false)1123 {1124 int rc;1125 1126 if (RT_SUCCESS(rc = RTDBusLoadLib()))1127 {1128 for (unsigned i = 0; RT_SUCCESS(rc) && i < 5 && !mConnection; ++i)1129 {1130 rc = halInitPrivate (&mConnection);1131 }1132 if (!mConnection)1133 rc = VERR_NOT_SUPPORTED;1134 DBusMessage *pMessage;1135 while ( RT_SUCCESS(rc)1136 && (pMessage = dbus_connection_pop_message (mConnection.get())) != NULL)1137 dbus_message_unref (pMessage); /* empty the message queue. */1138 if ( RT_SUCCESS(rc)1139 && !dbus_connection_add_filter (mConnection.get(),1140 dbusFilterFunction,1141 (void *) &mTriggered, NULL))1142 rc = VERR_NO_MEMORY;1143 if (RT_FAILURE(rc))1144 mConnection.reset();1145 }1146 mStatus = rc;1147 }1148 1149 /* Destructor */1150 hotplugDBusImpl::~hotplugDBusImpl ()1151 {1152 if (!!mConnection)1153 dbus_connection_remove_filter (mConnection.get(), dbusFilterFunction,1154 (void *) &mTriggered);1155 }1156 1157 /* Currently this is implemented using a timed out wait on our private DBus1158 * connection. Because the connection is private we don't have to worry about1159 * blocking other users. */1160 int hotplugDBusImpl::Wait(RTMSINTERVAL cMillies)1161 {1162 int rc = VINF_SUCCESS;1163 if (!mConnection)1164 rc = VERR_NOT_SUPPORTED;1165 bool connected = true;1166 mTriggered = false;1167 mInterrupt = false;1168 unsigned cRealMillies;1169 if (cMillies != RT_INDEFINITE_WAIT)1170 cRealMillies = cMillies;1171 else1172 cRealMillies = DBUS_POLL_TIMEOUT;1173 while ( RT_SUCCESS(rc) && connected && !mTriggered1174 && !mInterrupt)1175 {1176 connected = dbus_connection_read_write_dispatch (mConnection.get(),1177 cRealMillies);1178 if (mInterrupt)1179 LogFlowFunc(("wait loop interrupted\n"));1180 if (cMillies != RT_INDEFINITE_WAIT)1181 mInterrupt = true;1182 }1183 if (!connected)1184 rc = VERR_TRY_AGAIN;1185 return rc;1186 }1187 1188 /* Set a flag to tell the Wait not to resume next time it times out. */1189 void hotplugDBusImpl::Interrupt()1190 {1191 LogFlowFunc(("\n"));1192 mInterrupt = true;1193 }1194 #endif /* VBOX_USB_WITH_SYSFS && VBOX_USB_WITH_DBUS */1195 1020 1196 1021 class hotplugNullImpl : public VBoxMainHotplugWaiterImpl … … 1415 1240 /* For now this probing method should only be used if nothing else is 1416 1241 * available */ 1417 if (!testing())1418 {1419 # ifdef VBOX_USB_WITH_DBUS1420 Assert(!hotplugDBusImpl::Available());1421 # endif1422 }1423 1242 # endif 1424 1243 int rc; … … 1544 1363 { 1545 1364 #ifdef VBOX_USB_WITH_SYSFS 1546 # ifdef VBOX_WITH_DBUS1547 if (hotplugDBusImpl::Available())1548 {1549 mImpl = new hotplugDBusImpl;1550 return;1551 }1552 # endif /* VBOX_WITH_DBUS */1553 1365 # ifdef VBOX_USB_WITH_INOTIFY 1554 1366 if (hotplugInotifyImpl::Available()) … … 1815 1627 # endif /* VBOX_USB_WITH_INOTIFY */ 1816 1628 #endif /* VBOX_USB_WITH_SYSFS */ 1817 1818 #if defined VBOX_USB_WITH_SYSFS && defined VBOX_USB_WITH_DBUS1819 /** Wrapper class around DBusError for automatic cleanup */1820 class autoDBusError1821 {1822 DBusError mError;1823 public:1824 autoDBusError () { dbus_error_init (&mError); }1825 ~autoDBusError ()1826 {1827 if (IsSet())1828 dbus_error_free (&mError);1829 }1830 DBusError &get () { return mError; }1831 bool IsSet ()1832 {1833 Assert((mError.name == NULL) == (mError.message == NULL));1834 return (mError.name != NULL);1835 }1836 bool HasName (const char *pcszName)1837 {1838 Assert((mError.name == NULL) == (mError.message == NULL));1839 return (RTStrCmp (mError.name, pcszName) == 0);1840 }1841 void FlowLog ()1842 {1843 if (IsSet ())1844 LogFlow(("DBus error %s: %s\n", mError.name, mError.message));1845 }1846 };1847 1848 /**1849 * Helper function for setting up a connection to the DBus daemon and1850 * registering with the hal service.1851 *1852 * @note If libdbus is being loaded at runtime then be sure to call1853 * VBoxDBusCheckPresence before calling this.1854 * @returns iprt status code1855 * @param ppConnection where to store the connection handle1856 */1857 /* static */1858 int halInit (RTMemAutoPtr <DBusConnection, VBoxHalShutdown> *pConnection)1859 {1860 AssertReturn(VALID_PTR (pConnection), VERR_INVALID_POINTER);1861 LogFlowFunc (("pConnection=%p\n", pConnection));1862 int rc = VINF_SUCCESS;1863 bool halSuccess = true;1864 autoDBusError dbusError;1865 1866 RTMemAutoPtr <DBusConnection, VBoxDBusConnectionUnref> dbusConnection;1867 dbusConnection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbusError.get());1868 if (!dbusConnection)1869 halSuccess = false;1870 if (halSuccess)1871 {1872 dbus_connection_set_exit_on_disconnect (dbusConnection.get(), false);1873 halSuccess = dbus_bus_name_has_owner (dbusConnection.get(),1874 "org.freedesktop.Hal", &dbusError.get());1875 }1876 if (halSuccess)1877 {1878 dbus_bus_add_match (dbusConnection.get(),1879 "type='signal',"1880 "interface='org.freedesktop.Hal.Manager',"1881 "sender='org.freedesktop.Hal',"1882 "path='/org/freedesktop/Hal/Manager'",1883 &dbusError.get());1884 halSuccess = !dbusError.IsSet();1885 }1886 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))1887 rc = VERR_NO_MEMORY;1888 if (halSuccess)1889 *pConnection = dbusConnection.release();1890 LogFlowFunc(("rc=%Rrc, (*pConnection).get()=%p\n", rc, (*pConnection).get()));1891 dbusError.FlowLog();1892 return rc;1893 }1894 1895 /**1896 * Helper function for setting up a private connection to the DBus daemon and1897 * registering with the hal service. Private connections are considered1898 * unsociable and should not be used unnecessarily (as per the DBus API docs).1899 *1900 * @note If libdbus is being loaded at runtime then be sure to call1901 * VBoxDBusCheckPresence before calling this.1902 * @returns iprt status code1903 * @param pConnection where to store the connection handle1904 */1905 /* static */1906 int halInitPrivate (RTMemAutoPtr <DBusConnection, VBoxHalShutdownPrivate> *pConnection)1907 {1908 AssertReturn(VALID_PTR (pConnection), VERR_INVALID_POINTER);1909 LogFlowFunc (("pConnection=%p\n", pConnection));1910 int rc = VINF_SUCCESS;1911 bool halSuccess = true;1912 autoDBusError dbusError;1913 1914 RTMemAutoPtr <DBusConnection, VBoxDBusConnectionCloseAndUnref> dbusConnection;1915 dbusConnection = dbus_bus_get_private (DBUS_BUS_SYSTEM, &dbusError.get());1916 if (!dbusConnection)1917 halSuccess = false;1918 if (halSuccess)1919 {1920 dbus_connection_set_exit_on_disconnect (dbusConnection.get(), false);1921 halSuccess = dbus_bus_name_has_owner (dbusConnection.get(),1922 "org.freedesktop.Hal", &dbusError.get());1923 }1924 if (halSuccess)1925 {1926 dbus_bus_add_match (dbusConnection.get(),1927 "type='signal',"1928 "interface='org.freedesktop.Hal.Manager',"1929 "sender='org.freedesktop.Hal',"1930 "path='/org/freedesktop/Hal/Manager'",1931 &dbusError.get());1932 halSuccess = !dbusError.IsSet();1933 }1934 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))1935 rc = VERR_NO_MEMORY;1936 if (halSuccess)1937 *pConnection = dbusConnection.release();1938 LogFlowFunc(("rc=%Rrc, (*pConnection).get()=%p\n", rc, (*pConnection).get()));1939 dbusError.FlowLog();1940 return rc;1941 }1942 1943 /**1944 * Helper function for shutting down a connection to DBus and hal.1945 * @param pConnection the connection handle1946 */1947 /* extern */1948 void VBoxHalShutdown (DBusConnection *pConnection)1949 {1950 AssertReturnVoid(VALID_PTR (pConnection));1951 LogFlowFunc (("pConnection=%p\n", pConnection));1952 autoDBusError dbusError;1953 1954 dbus_bus_remove_match (pConnection,1955 "type='signal',"1956 "interface='org.freedesktop.Hal.Manager',"1957 "sender='org.freedesktop.Hal',"1958 "path='/org/freedesktop/Hal/Manager'",1959 &dbusError.get());1960 dbus_connection_unref (pConnection);1961 LogFlowFunc(("returning\n"));1962 dbusError.FlowLog();1963 }1964 1965 /**1966 * Helper function for shutting down a private connection to DBus and hal.1967 * @param pConnection the connection handle1968 */1969 /* extern */1970 void VBoxHalShutdownPrivate (DBusConnection *pConnection)1971 {1972 AssertReturnVoid(VALID_PTR (pConnection));1973 LogFlowFunc (("pConnection=%p\n", pConnection));1974 autoDBusError dbusError;1975 1976 dbus_bus_remove_match (pConnection,1977 "type='signal',"1978 "interface='org.freedesktop.Hal.Manager',"1979 "sender='org.freedesktop.Hal',"1980 "path='/org/freedesktop/Hal/Manager'",1981 &dbusError.get());1982 dbus_connection_close (pConnection);1983 dbus_connection_unref (pConnection);1984 LogFlowFunc(("returning\n"));1985 dbusError.FlowLog();1986 }1987 1988 /** Wrapper around dbus_connection_unref. We need this to use it as a real1989 * function in auto pointers, as a function pointer won't wash here. */1990 /* extern */1991 void VBoxDBusConnectionUnref(DBusConnection *pConnection)1992 {1993 dbus_connection_unref(pConnection);1994 }1995 1996 /**1997 * This function closes and unrefs a private connection to dbus. It should1998 * only be called once no-one else is referencing the connection.1999 */2000 /* extern */2001 void VBoxDBusConnectionCloseAndUnref(DBusConnection *pConnection)2002 {2003 dbus_connection_close(pConnection);2004 dbus_connection_unref(pConnection);2005 }2006 2007 /** Wrapper around dbus_message_unref. We need this to use it as a real2008 * function in auto pointers, as a function pointer won't wash here. */2009 /* extern */2010 void VBoxDBusMessageUnref(DBusMessage *pMessage)2011 {2012 dbus_message_unref(pMessage);2013 }2014 2015 /**2016 * Find the UDIs of hal entries that contain Key=Value property.2017 * @returns iprt status code. If a non-fatal error occurs, we return success2018 * but reset pMessage to NULL.2019 * @param pConnection an initialised connection DBus2020 * @param pszKey the property key2021 * @param pszValue the property value2022 * @param pMessage where to store the return DBus message. This must be2023 * parsed to get at the UDIs. NOT optional.2024 */2025 /* static */2026 int halFindDeviceStringMatch (DBusConnection *pConnection, const char *pszKey,2027 const char *pszValue,2028 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage)2029 {2030 AssertReturn( VALID_PTR (pConnection) && VALID_PTR (pszKey)2031 && VALID_PTR (pszValue) && VALID_PTR (pMessage),2032 VERR_INVALID_POINTER);2033 LogFlowFunc (("pConnection=%p, pszKey=%s, pszValue=%s, pMessage=%p\n",2034 pConnection, pszKey, pszValue, pMessage));2035 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */2036 bool halSuccess = true; /* We set this to false to abort the operation. */2037 autoDBusError dbusError;2038 2039 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, reply;2040 if (halSuccess && RT_SUCCESS(rc))2041 {2042 message = dbus_message_new_method_call ("org.freedesktop.Hal",2043 "/org/freedesktop/Hal/Manager",2044 "org.freedesktop.Hal.Manager",2045 "FindDeviceStringMatch");2046 if (!message)2047 rc = VERR_NO_MEMORY;2048 }2049 if (halSuccess && RT_SUCCESS(rc))2050 {2051 DBusMessageIter iterAppend;2052 dbus_message_iter_init_append (message.get(), &iterAppend);2053 dbus_message_iter_append_basic (&iterAppend, DBUS_TYPE_STRING, &pszKey);2054 dbus_message_iter_append_basic (&iterAppend, DBUS_TYPE_STRING, &pszValue);2055 reply = dbus_connection_send_with_reply_and_block (pConnection,2056 message.get(), -1,2057 &dbusError.get());2058 if (!reply)2059 halSuccess = false;2060 }2061 *pMessage = reply.release ();2062 LogFlowFunc (("rc=%Rrc, *pMessage.value()=%p\n", rc, (*pMessage).get()));2063 dbusError.FlowLog();2064 return rc;2065 }2066 2067 /**2068 * Find the UDIs of hal entries that contain Key=Value property and return the2069 * result on the end of a vector of iprt::MiniString.2070 * @returns iprt status code. If a non-fatal error occurs, we return success2071 * but set *pfSuccess to false.2072 * @param pConnection an initialised connection DBus2073 * @param pszKey the property key2074 * @param pszValue the property value2075 * @param pMatches pointer to an array of iprt::MiniString to append the2076 * results to. NOT optional.2077 * @param pfSuccess will be set to true if the operation succeeds2078 */2079 /* static */2080 int halFindDeviceStringMatchVector (DBusConnection *pConnection,2081 const char *pszKey, const char *pszValue,2082 std::vector<iprt::MiniString> *pMatches,2083 bool *pfSuccess)2084 {2085 AssertPtrReturn (pConnection, VERR_INVALID_POINTER);2086 AssertPtrReturn (pszKey, VERR_INVALID_POINTER);2087 AssertPtrReturn (pszValue, VERR_INVALID_POINTER);2088 AssertPtrReturn (pMatches, VERR_INVALID_POINTER);2089 AssertReturn(pfSuccess == NULL || VALID_PTR (pfSuccess), VERR_INVALID_POINTER);2090 LogFlowFunc (("pConnection=%p, pszKey=%s, pszValue=%s, pMatches=%p, pfSuccess=%p\n",2091 pConnection, pszKey, pszValue, pMatches, pfSuccess));2092 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */2093 bool halSuccess = true; /* We set this to false to abort the operation. */2094 2095 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, replyFind;2096 DBusMessageIter iterFind, iterUdis;2097 2098 if (halSuccess && RT_SUCCESS(rc))2099 {2100 rc = halFindDeviceStringMatch (pConnection, pszKey, pszValue,2101 &replyFind);2102 if (!replyFind)2103 halSuccess = false;2104 }2105 if (halSuccess && RT_SUCCESS(rc))2106 {2107 dbus_message_iter_init (replyFind.get(), &iterFind);2108 if (dbus_message_iter_get_arg_type (&iterFind) != DBUS_TYPE_ARRAY)2109 halSuccess = false;2110 }2111 if (halSuccess && RT_SUCCESS(rc))2112 dbus_message_iter_recurse (&iterFind, &iterUdis);2113 for (; halSuccess && RT_SUCCESS(rc)2114 && dbus_message_iter_get_arg_type (&iterUdis) == DBUS_TYPE_STRING;2115 dbus_message_iter_next(&iterUdis))2116 {2117 /* Now get all UDIs from the iterator */2118 const char *pszUdi;2119 dbus_message_iter_get_basic (&iterUdis, &pszUdi);2120 try2121 {2122 pMatches->push_back(pszUdi);2123 }2124 catch(std::bad_alloc &e)2125 {2126 rc = VERR_NO_MEMORY;2127 }2128 }2129 if (pfSuccess != NULL)2130 *pfSuccess = halSuccess;2131 LogFlow (("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));2132 return rc;2133 }2134 2135 /**2136 * Read a set of string properties for a device. If some of the properties are2137 * not of type DBUS_TYPE_STRING or do not exist then a NULL pointer will be2138 * returned for them.2139 * @returns iprt status code. If the operation failed for non-fatal reasons2140 * then we return success and leave pMessage untouched - reset it2141 * before the call to detect this.2142 * @param pConnection an initialised connection DBus2143 * @param pszUdi the Udi of the device2144 * @param cProps the number of property values to look up2145 * @param papszKeys the keys of the properties to be looked up2146 * @param papszValues where to store the values of the properties. The2147 * strings returned will be valid until the message2148 * returned in @a ppMessage is freed. Undefined if2149 * the message is NULL.2150 * @param pMessage where to store the return DBus message. The caller2151 * is responsible for freeing this once they have2152 * finished with the value strings. NOT optional.2153 */2154 /* static */2155 int halGetPropertyStrings (DBusConnection *pConnection, const char *pszUdi,2156 size_t cProps, const char **papszKeys,2157 char **papszValues,2158 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage)2159 {2160 AssertReturn( VALID_PTR (pConnection) && VALID_PTR (pszUdi)2161 && VALID_PTR (papszKeys) && VALID_PTR (papszValues)2162 && VALID_PTR (pMessage),2163 VERR_INVALID_POINTER);2164 LogFlowFunc (("pConnection=%p, pszUdi=%s, cProps=%llu, papszKeys=%p, papszValues=%p, pMessage=%p\n",2165 pConnection, pszUdi, cProps, papszKeys, papszValues, pMessage));2166 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */2167 bool halSuccess = true; /* We set this to false to abort the operation. */2168 autoDBusError dbusError;2169 2170 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, reply;2171 DBusMessageIter iterGet, iterProps;2172 2173 /* Initialise the return array to NULLs */2174 for (size_t i = 0; i < cProps; ++i)2175 papszValues[i] = NULL;2176 2177 /* Send a GetAllProperties message to hald */2178 message = dbus_message_new_method_call ("org.freedesktop.Hal", pszUdi,2179 "org.freedesktop.Hal.Device",2180 "GetAllProperties");2181 if (!message)2182 rc = VERR_NO_MEMORY;2183 if (halSuccess && RT_SUCCESS(rc))2184 {2185 reply = dbus_connection_send_with_reply_and_block (pConnection,2186 message.get(), -1,2187 &dbusError.get());2188 if (!reply)2189 halSuccess = false;2190 }2191 2192 /* Parse the reply */2193 if (halSuccess && RT_SUCCESS(rc))2194 {2195 dbus_message_iter_init (reply.get(), &iterGet);2196 if ( dbus_message_iter_get_arg_type (&iterGet) != DBUS_TYPE_ARRAY2197 && dbus_message_iter_get_element_type (&iterGet) != DBUS_TYPE_DICT_ENTRY)2198 halSuccess = false;2199 }2200 if (halSuccess && RT_SUCCESS(rc))2201 dbus_message_iter_recurse (&iterGet, &iterProps);2202 /* Go through all entries in the reply and see if any match our keys. */2203 while ( halSuccess && RT_SUCCESS(rc)2204 && dbus_message_iter_get_arg_type (&iterProps)2205 == DBUS_TYPE_DICT_ENTRY)2206 {2207 const char *pszKey;2208 DBusMessageIter iterEntry, iterValue;2209 dbus_message_iter_recurse (&iterProps, &iterEntry);2210 dbus_message_iter_get_basic (&iterEntry, &pszKey);2211 dbus_message_iter_next (&iterEntry);2212 dbus_message_iter_recurse (&iterEntry, &iterValue);2213 /* Fill in any matches. */2214 for (size_t i = 0; i < cProps; ++i)2215 if (strcmp (pszKey, papszKeys[i]) == 0)2216 {2217 if (dbus_message_iter_get_arg_type (&iterValue) == DBUS_TYPE_STRING)2218 dbus_message_iter_get_basic (&iterValue, &papszValues[i]);2219 }2220 dbus_message_iter_next (&iterProps);2221 }2222 if (RT_SUCCESS(rc) && halSuccess)2223 *pMessage = reply.release();2224 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))2225 rc = VERR_NO_MEMORY;2226 LogFlowFunc (("rc=%Rrc, *pMessage.value()=%p\n", rc, (*pMessage).get()));2227 dbusError.FlowLog();2228 return rc;2229 }2230 2231 /**2232 * Read a set of string properties for a device. If some properties do not2233 * exist or are not of type DBUS_TYPE_STRING, we will still fetch the others.2234 * @returns iprt status code. If the operation failed for non-fatal reasons2235 * then we return success and set *pfSuccess to false.2236 * @param pConnection an initialised connection DBus2237 * @param pszUdi the Udi of the device2238 * @param cProps the number of property values to look up2239 * @param papszKeys the keys of the properties to be looked up2240 * @param pMatches pointer to an empty array of iprt::MiniString to append the2241 * results to. NOT optional.2242 * @param pfMatches pointer to an array of boolean values indicating2243 * whether the respective property is a string. If this2244 * is not supplied then all properties must be strings2245 * for the operation to be considered successful2246 * @param pfSuccess will be set to true if the operation succeeds2247 */2248 /* static */2249 int halGetPropertyStringsVector (DBusConnection *pConnection,2250 const char *pszUdi, size_t cProps,2251 const char **papszKeys,2252 std::vector<iprt::MiniString> *pMatches,2253 bool *pfMatches, bool *pfSuccess)2254 {2255 AssertPtrReturn (pConnection, VERR_INVALID_POINTER);2256 AssertPtrReturn (pszUdi, VERR_INVALID_POINTER);2257 AssertPtrReturn (papszKeys, VERR_INVALID_POINTER);2258 AssertPtrReturn (pMatches, VERR_INVALID_POINTER);2259 AssertReturn((pfMatches == NULL) || VALID_PTR (pfMatches), VERR_INVALID_POINTER);2260 AssertReturn((pfSuccess == NULL) || VALID_PTR (pfSuccess), VERR_INVALID_POINTER);2261 AssertReturn(pMatches->empty(), VERR_INVALID_PARAMETER);2262 LogFlowFunc (("pConnection=%p, pszUdi=%s, cProps=%llu, papszKeys=%p, pMatches=%p, pfMatches=%p, pfSuccess=%p\n",2263 pConnection, pszUdi, cProps, papszKeys, pMatches, pfMatches, pfSuccess));2264 RTMemAutoPtr <char *> values(cProps);2265 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message;2266 bool halSuccess = true;2267 int rc = halGetPropertyStrings (pConnection, pszUdi, cProps, papszKeys,2268 values.get(), &message);2269 if (!message)2270 halSuccess = false;2271 for (size_t i = 0; RT_SUCCESS(rc) && halSuccess && i < cProps; ++i)2272 {2273 bool fMatches = values[i] != NULL;2274 if (pfMatches != NULL)2275 pfMatches[i] = fMatches;2276 else2277 halSuccess = fMatches;2278 try2279 {2280 pMatches->push_back(fMatches ? values[i] : "");2281 }2282 catch(std::bad_alloc &e)2283 {2284 rc = VERR_NO_MEMORY;2285 }2286 }2287 if (pfSuccess != NULL)2288 *pfSuccess = halSuccess;2289 if (RT_SUCCESS(rc) && halSuccess)2290 {2291 Assert(pMatches->size() == cProps);2292 AssertForEach(j, size_t, 0, cProps, (pfMatches == NULL)2293 || (pfMatches[j] == true)2294 || ((pfMatches[j] == false) && (pMatches[j].size() == 0)));2295 }2296 LogFlowFunc (("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));2297 return rc;2298 }2299 2300 2301 /**2302 * Helper function to query the hal subsystem for information about USB devices2303 * attached to the system.2304 * @returns iprt status code2305 * @param pList where to add information about the devices detected2306 * @param pfSuccess will be set to true if all interactions with hal2307 * succeeded and to false otherwise. Optional.2308 *2309 * @returns IPRT status code2310 */2311 /* static */2312 int getUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess)2313 {2314 AssertReturn(VALID_PTR (pList) && (pfSuccess == NULL || VALID_PTR (pfSuccess)),2315 VERR_INVALID_POINTER);2316 LogFlowFunc (("pList=%p, pfSuccess=%p\n", pList, pfSuccess));2317 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */2318 bool halSuccess = true; /* We set this to false to abort the operation. */2319 autoDBusError dbusError;2320 2321 RTMemAutoPtr<DBusMessage, VBoxDBusMessageUnref> message, replyFind, replyGet;2322 RTMemAutoPtr<DBusConnection, VBoxHalShutdown> dbusConnection;2323 DBusMessageIter iterFind, iterUdis;2324 2325 /* Connect to hal */2326 rc = halInit (&dbusConnection);2327 if (!dbusConnection)2328 halSuccess = false;2329 /* Get an array of all devices in the usb_device subsystem */2330 if (halSuccess && RT_SUCCESS(rc))2331 {2332 rc = halFindDeviceStringMatch(dbusConnection.get(), "info.subsystem",2333 "usb_device", &replyFind);2334 if (!replyFind)2335 halSuccess = false;2336 }2337 if (halSuccess && RT_SUCCESS(rc))2338 {2339 dbus_message_iter_init(replyFind.get(), &iterFind);2340 if (dbus_message_iter_get_arg_type (&iterFind) != DBUS_TYPE_ARRAY)2341 halSuccess = false;2342 }2343 /* Recurse down into the array and query interesting information about the2344 * entries. */2345 if (halSuccess && RT_SUCCESS(rc))2346 dbus_message_iter_recurse(&iterFind, &iterUdis);2347 for (; halSuccess && RT_SUCCESS(rc)2348 && dbus_message_iter_get_arg_type(&iterUdis) == DBUS_TYPE_STRING;2349 dbus_message_iter_next(&iterUdis))2350 {2351 /* Get the device node and the sysfs path for the current entry. */2352 const char *pszUdi;2353 dbus_message_iter_get_basic (&iterUdis, &pszUdi);2354 static const char *papszKeys[] = { "linux.device_file", "linux.sysfs_path" };2355 char *papszValues[RT_ELEMENTS(papszKeys)];2356 rc = halGetPropertyStrings(dbusConnection.get(), pszUdi, RT_ELEMENTS(papszKeys),2357 papszKeys, papszValues, &replyGet);2358 const char *pszDevice = papszValues[0], *pszSysfsPath = papszValues[1];2359 /* Get the interfaces. */2360 if (!!replyGet && pszDevice && pszSysfsPath)2361 {2362 USBDeviceInfo info(pszDevice, pszSysfsPath);2363 bool ifaceSuccess = true; /* If we can't get the interfaces, just2364 * skip this one device. */2365 rc = getUSBInterfacesFromHal(&info.mInterfaces, pszUdi, &ifaceSuccess);2366 if (RT_SUCCESS(rc) && halSuccess && ifaceSuccess)2367 try2368 {2369 pList->push_back(info);2370 }2371 catch(std::bad_alloc &e)2372 {2373 rc = VERR_NO_MEMORY;2374 }2375 }2376 }2377 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))2378 rc = VERR_NO_MEMORY;2379 if (pfSuccess != NULL)2380 *pfSuccess = halSuccess;2381 LogFlow(("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));2382 dbusError.FlowLog();2383 return rc;2384 }2385 2386 /**2387 * Helper function to query the hal subsystem for information about USB devices2388 * attached to the system, using the older API.2389 * @returns iprt status code2390 * @param pList where to add information about the devices detected2391 * @param pfSuccess will be set to true if all interactions with hal2392 * succeeded and to false otherwise. Optional.2393 *2394 * @returns IPRT status code2395 */2396 /* static */2397 int getOldUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess)2398 {2399 AssertReturn(VALID_PTR (pList) && (pfSuccess == NULL || VALID_PTR (pfSuccess)),2400 VERR_INVALID_POINTER);2401 LogFlowFunc (("pList=%p, pfSuccess=%p\n", pList, pfSuccess));2402 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */2403 bool halSuccess = true; /* We set this to false to abort the operation. */2404 autoDBusError dbusError;2405 2406 RTMemAutoPtr<DBusMessage, VBoxDBusMessageUnref> message, replyFind, replyGet;2407 RTMemAutoPtr<DBusConnection, VBoxHalShutdown> dbusConnection;2408 DBusMessageIter iterFind, iterUdis;2409 2410 /* Connect to hal */2411 rc = halInit(&dbusConnection);2412 if (!dbusConnection)2413 halSuccess = false;2414 /* Get an array of all devices in the usb_device subsystem */2415 if (halSuccess && RT_SUCCESS(rc))2416 {2417 rc = halFindDeviceStringMatch(dbusConnection.get(), "info.category",2418 "usbraw", &replyFind);2419 if (!replyFind)2420 halSuccess = false;2421 }2422 if (halSuccess && RT_SUCCESS(rc))2423 {2424 dbus_message_iter_init(replyFind.get(), &iterFind);2425 if (dbus_message_iter_get_arg_type(&iterFind) != DBUS_TYPE_ARRAY)2426 halSuccess = false;2427 }2428 /* Recurse down into the array and query interesting information about the2429 * entries. */2430 if (halSuccess && RT_SUCCESS(rc))2431 dbus_message_iter_recurse(&iterFind, &iterUdis);2432 for (; halSuccess && RT_SUCCESS(rc)2433 && dbus_message_iter_get_arg_type(&iterUdis) == DBUS_TYPE_STRING;2434 dbus_message_iter_next(&iterUdis))2435 {2436 /* Get the device node and the sysfs path for the current entry. */2437 const char *pszUdi;2438 dbus_message_iter_get_basic(&iterUdis, &pszUdi);2439 static const char *papszKeys[] = { "linux.device_file", "info.parent" };2440 char *papszValues[RT_ELEMENTS(papszKeys)];2441 rc = halGetPropertyStrings(dbusConnection.get(), pszUdi, RT_ELEMENTS(papszKeys),2442 papszKeys, papszValues, &replyGet);2443 const char *pszDevice = papszValues[0], *pszSysfsPath = papszValues[1];2444 /* Get the interfaces. */2445 if (!!replyGet && pszDevice && pszSysfsPath)2446 {2447 USBDeviceInfo info(pszDevice, pszSysfsPath);2448 bool ifaceSuccess = false; /* If we can't get the interfaces, just2449 * skip this one device. */2450 rc = getUSBInterfacesFromHal(&info.mInterfaces, pszSysfsPath,2451 &ifaceSuccess);2452 if (RT_SUCCESS(rc) && halSuccess && ifaceSuccess)2453 try2454 {2455 pList->push_back(info);2456 }2457 catch(std::bad_alloc &e)2458 {2459 rc = VERR_NO_MEMORY;2460 }2461 }2462 }2463 if (dbusError.HasName(DBUS_ERROR_NO_MEMORY))2464 rc = VERR_NO_MEMORY;2465 if (pfSuccess != NULL)2466 *pfSuccess = halSuccess;2467 LogFlow(("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));2468 dbusError.FlowLog();2469 return rc;2470 }2471 2472 2473 /**2474 * Helper function to query the hal subsystem for information about USB devices2475 * attached to the system.2476 * @returns iprt status code2477 * @param pList where to add information about the devices detected. If2478 * certain interfaces are not found (@a pfFound is false on2479 * return) this may contain invalid information.2480 * @param pcszUdi the hal UDI of the device2481 * @param pfSuccess will be set to true if the operation succeeds and to2482 * false if it fails for non-critical reasons. Optional.2483 *2484 * @returns IPRT status code2485 */2486 /* static */2487 int getUSBInterfacesFromHal(std::vector<iprt::MiniString> *pList,2488 const char *pcszUdi, bool *pfSuccess)2489 {2490 AssertReturn(VALID_PTR(pList) && VALID_PTR(pcszUdi) &&2491 (pfSuccess == NULL || VALID_PTR (pfSuccess)),2492 VERR_INVALID_POINTER);2493 LogFlowFunc(("pList=%p, pcszUdi=%s, pfSuccess=%p\n", pList, pcszUdi,2494 pfSuccess));2495 int rc = VINF_SUCCESS; /* We set this to failure on fatal errors. */2496 bool halSuccess = true; /* We set this to false to abort the operation. */2497 autoDBusError dbusError;2498 2499 RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> message, replyFind, replyGet;2500 RTMemAutoPtr <DBusConnection, VBoxHalShutdown> dbusConnection;2501 DBusMessageIter iterFind, iterUdis;2502 2503 rc = halInit(&dbusConnection);2504 if (!dbusConnection)2505 halSuccess = false;2506 if (halSuccess && RT_SUCCESS(rc))2507 {2508 /* Look for children of the current UDI. */2509 rc = halFindDeviceStringMatch(dbusConnection.get(), "info.parent",2510 pcszUdi, &replyFind);2511 if (!replyFind)2512 halSuccess = false;2513 }2514 if (halSuccess && RT_SUCCESS(rc))2515 {2516 dbus_message_iter_init(replyFind.get(), &iterFind);2517 if (dbus_message_iter_get_arg_type(&iterFind) != DBUS_TYPE_ARRAY)2518 halSuccess = false;2519 }2520 if (halSuccess && RT_SUCCESS(rc))2521 dbus_message_iter_recurse(&iterFind, &iterUdis);2522 for (; halSuccess && RT_SUCCESS(rc)2523 && dbus_message_iter_get_arg_type(&iterUdis) == DBUS_TYPE_STRING;2524 dbus_message_iter_next(&iterUdis))2525 {2526 /* Now get the sysfs path and the subsystem from the iterator */2527 const char *pszUdi;2528 dbus_message_iter_get_basic(&iterUdis, &pszUdi);2529 static const char *papszKeys[] = { "linux.sysfs_path", "info.subsystem",2530 "linux.subsystem" };2531 char *papszValues[RT_ELEMENTS(papszKeys)];2532 rc = halGetPropertyStrings(dbusConnection.get(), pszUdi, RT_ELEMENTS(papszKeys),2533 papszKeys, papszValues, &replyGet);2534 const char *pszSysfsPath = papszValues[0], *pszInfoSubsystem = papszValues[1],2535 *pszLinuxSubsystem = papszValues[2];2536 if (!replyGet)2537 halSuccess = false;2538 if (!!replyGet && pszSysfsPath == NULL)2539 halSuccess = false;2540 if ( halSuccess && RT_SUCCESS(rc)2541 && RTStrCmp (pszInfoSubsystem, "usb_device") != 0 /* Children of buses can also be devices. */2542 && RTStrCmp (pszLinuxSubsystem, "usb_device") != 0)2543 try2544 {2545 pList->push_back(pszSysfsPath);2546 }2547 catch(std::bad_alloc &e)2548 {2549 rc = VERR_NO_MEMORY;2550 }2551 }2552 if (dbusError.HasName(DBUS_ERROR_NO_MEMORY))2553 rc = VERR_NO_MEMORY;2554 if (pfSuccess != NULL)2555 *pfSuccess = halSuccess;2556 LogFlow(("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));2557 dbusError.FlowLog();2558 return rc;2559 }2560 2561 /**2562 * When it is registered with DBus, this function will be called by2563 * dbus_connection_read_write_dispatch each time a message is received over the2564 * DBus connection. We check whether that message was caused by a hal device2565 * hotplug event, and if so we set a flag. dbus_connection_read_write_dispatch2566 * will return after calling its filter functions, and its caller should then2567 * check the status of the flag passed to the filter function.2568 *2569 * @param pConnection The DBus connection we are using.2570 * @param pMessage The DBus message which just arrived.2571 * @param pvUser A pointer to the flag variable we are to set.2572 */2573 /* static */2574 DBusHandlerResult dbusFilterFunction(DBusConnection * /* pConnection */,2575 DBusMessage *pMessage, void *pvUser)2576 {2577 volatile bool *pTriggered = reinterpret_cast<volatile bool *>(pvUser);2578 if ( dbus_message_is_signal(pMessage, "org.freedesktop.Hal.Manager",2579 "DeviceAdded")2580 || dbus_message_is_signal(pMessage, "org.freedesktop.Hal.Manager",2581 "DeviceRemoved"))2582 {2583 *pTriggered = true;2584 }2585 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;2586 }2587 #endif /* VBOX_USB_WITH_SYSFS && VBOX_USB_WITH_DBUS */2588 -
trunk/src/VBox/Main/testcase/tstHostHardwareLinux.cpp
r30265 r31564 146 146 } 147 147 VBoxMainHotplugWaiter waiter; 148 RTPrintf ("Waiting for hotplug events. Note that DBus often seems to deliver duplicate events in close succession.\n");149 148 RTPrintf ("Waiting for a hotplug event for five seconds...\n"); 150 149 doHotplugEvent(&waiter, 5000);
Note:
See TracChangeset
for help on using the changeset viewer.