Changeset 28309 in vbox
- Timestamp:
- Apr 14, 2010 3:22:16 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 60067
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/linux/HostHardwareLinux.cpp
r26296 r28309 93 93 static int getDriveInfoFromSysfs(DriveInfoList *pList, bool isDVD, 94 94 bool *pfSuccess); 95 static int getUSBDeviceInfoFromSysfs(USBDeviceInfoList *pList, bool *pfSuccess); 95 96 #ifdef VBOX_WITH_DBUS 96 97 /* These must be extern to be usable in the RTMemAutoPtr template */ … … 1039 1040 success = halSuccess; 1040 1041 #endif /* VBOX_WITH_DBUS defined */ 1042 if ( RT_SUCCESS(rc) 1043 && (!success || testing())) 1044 rc = getUSBDeviceInfoFromSysfs(&mDeviceList, &halSuccess); 1041 1045 #endif /* RT_OS_LINUX */ 1042 1046 } … … 1806 1810 return rc; 1807 1811 } 1812 1813 class sysfsPathHandler 1814 { 1815 /** Called on each element of the sysfs directory. Can e.g. store 1816 * interesting entries in a list. */ 1817 virtual bool handle(const char *pcszNode) = 0; 1818 public: 1819 bool doHandle(const char *pcszNode) 1820 { 1821 AssertPtr(pcszNode); 1822 Assert(pcszNode[0] == '/'); 1823 Assert(RTPathExists(pcszNode)); 1824 return handle(pcszNode); 1825 } 1826 }; 1827 1828 /** 1829 * Helper function to walk a sysfs directory for extracting information about 1830 * devices. 1831 * @returns iprt status code 1832 * @param pcszPath Sysfs directory to walk. Must exist. 1833 * @param pHandler Handler object which will be invoked on each directory 1834 * entry 1835 * 1836 * @returns IPRT status code 1837 */ 1838 /* static */ 1839 int getDeviceInfoFromSysfs(const char *pcszPath, sysfsPathHandler *pHandler) 1840 { 1841 AssertPtrReturn(pcszPath, VERR_INVALID_POINTER); 1842 AssertPtrReturn(pHandler, VERR_INVALID_POINTER); 1843 LogFlowFunc (("pcszPath=%s, pHandler=%p\n", pcszPath, pHandler)); 1844 PRTDIR pDir = NULL; 1845 int rc; 1846 1847 rc = RTDirOpen(&pDir, pcszPath); 1848 AssertRCReturn(rc, rc); 1849 while (RT_SUCCESS(rc)) 1850 { 1851 RTDIRENTRY entry; 1852 char szPath[RTPATH_MAX], szAbsPath[RTPATH_MAX]; 1853 1854 rc = RTDirRead(pDir, &entry, NULL); 1855 Assert(rc != VERR_BUFFER_OVERFLOW); /* Should never happen... */ 1856 /* We break on "no more files" as well as on "real" errors */ 1857 if (RT_FAILURE(rc)) 1858 break; 1859 if (entry.szName[0] == '.') 1860 continue; 1861 if (RTStrPrintf(szPath, sizeof(szPath), "%s/%s", pcszPath, 1862 entry.szName) >= sizeof(szPath)) 1863 rc = VERR_BUFFER_OVERFLOW; 1864 if (RT_FAILURE(rc)) 1865 break; 1866 rc = RTPathReal(szPath, szAbsPath, sizeof(szAbsPath)); 1867 AssertRCBreak(rc)); /* sysfs should guarantee that this exists */ 1868 if (!pHandler->doHandle(szAbsPath)) 1869 break; 1870 } 1871 RTDirClose(pDir); 1872 if (rc == VERR_NO_MORE_FILES) 1873 rc = VINF_SUCCESS; 1874 LogFlow (("rc=%Rrc\n", rc)); 1875 return rc; 1876 } 1877 1878 1879 /** 1880 * Tell whether a file in /sys/bus/usb/devices is a device rather than an 1881 * interface. To be used with getDeviceInfoFromSysfs(). 1882 */ 1883 class matchUSBDevice : public sysfsPathHandler 1884 { 1885 USBDeviceInfoList *mList; 1886 public: 1887 matchUSBDevice(USBDeviceInfoList *pList) : mList(pList) {} 1888 private: 1889 virtual bool handle(const char *pcszNode) 1890 { 1891 const char *pcszFile = strrchr(pcszNode, '/'); 1892 if (strchr(pcszFile, ':')) 1893 return true; 1894 dev_t devnum = RTLinuxSysFsReadDevNumFile("%s/dev", pcszNode); 1895 AssertReturn (devnum, true); 1896 char szDevPath[RTPATH_MAX]; 1897 ssize_t cchDevPath; 1898 cchDevPath = RTLinuxFindDevicePath(devnum, RTFS_TYPE_DEV_CHAR, 1899 szDevPath, sizeof(szDevPath), 1900 "/dev/bus/usb/%.3d/%.3d", 1901 RTLinuxSysFsReadIntFile(10, "%s/busnum", pcszNode), 1902 RTLinuxSysFsReadIntFile(10, "%s/devnum", pcszNode)); 1903 if (cchDevPath < 0) 1904 return true; 1905 try 1906 { 1907 mList->push_back(USBDeviceInfo(szDevPath, pcszNode)); 1908 } 1909 catch(std::bad_alloc &e) 1910 { 1911 return false; 1912 } 1913 return true; 1914 } 1915 }; 1916 1917 /** 1918 * Tell whether a file in /sys/bus/usb/devices is an interface rather than a 1919 * device. To be used with getDeviceInfoFromSysfs(). 1920 */ 1921 class matchUSBInterface : public sysfsPathHandler 1922 { 1923 USBDeviceInfo *mInfo; 1924 public: 1925 /** This constructor is currently used to unit test the class logic in 1926 * debug builds. Since no access is made to anything outside the class, 1927 * this shouldn't cause any slowdown worth mentioning. */ 1928 matchUSBInterface(USBDeviceInfo *pInfo) : mInfo(pInfo) 1929 { 1930 Assert(isAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0", 1931 "/sys/devices/pci0000:00/0000:00:1a.0/usb3")); 1932 Assert(!isAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-1", 1933 "/sys/devices/pci0000:00/0000:00:1a.0/usb3")); 1934 Assert(!isAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/driver", 1935 "/sys/devices/pci0000:00/0000:00:1a.0/usb3")); 1936 } 1937 private: 1938 /** The logic for testing whether a sysfs address corresponds to an 1939 * interface of a device. Both must be referenced by their canonical 1940 * sysfs paths. This is not tested, as the test requires file-system 1941 * interaction. */ 1942 bool isAnInterfaceOf(const char *pcszIface, const char *pcszDev) 1943 { 1944 size_t cchDev = strlen(pcszDev); 1945 1946 AssertPtr(pcszIface); 1947 AssertPtr(pcszDev); 1948 Assert(pcszIface[0] == '/'); 1949 Assert(pcszDev[0] == '/'); 1950 Assert(pcszDev[cchDev - 1] != '/'); 1951 /* If this passes, pcszIface is at least cchDev long */ 1952 if (strncmp(pcszIface, pcszDev, cchDev)) 1953 return false; 1954 /* If this passes, pcszIface is longer than cchDev */ 1955 if (pcszIface[cchDev] != '/') 1956 return false; 1957 /* In sysfs an interface is an immediate subdirectory of the device */ 1958 if (strchr(pcszIface + cchDev + 1, '/')) 1959 return false; 1960 /* And it always has a colon in its name */ 1961 if (!strchr(pcszIface + cchDev + 1, ':')) 1962 return false; 1963 /* And hopefully we have now elimitated everything else */ 1964 return true; 1965 } 1966 1967 virtual bool handle(const char *pcszNode) 1968 { 1969 if (!isAnInterfaceOf(pcszNode, mInfo->mSysfsPath.c_str())) 1970 return true; 1971 try 1972 { 1973 mInfo->mInterfaces.push_back(pcszNode); 1974 } 1975 catch(std::bad_alloc &e) 1976 { 1977 return false; 1978 } 1979 return true; 1980 } 1981 }; 1982 1983 /** 1984 * Helper function to query the sysfs subsystem for information about USB 1985 * devices attached to the system. 1986 * @returns iprt status code 1987 * @param pList where to add information about the drives detected 1988 * @param pfSuccess Did we find anything? 1989 * 1990 * @returns IPRT status code 1991 */ 1992 static int getUSBDeviceInfoFromSysfs(USBDeviceInfoList *pList, 1993 bool *pfSuccess) 1994 { 1995 AssertPtrReturn(pList, VERR_INVALID_POINTER); 1996 AssertPtrNullReturn(pfSuccess, VERR_INVALID_POINTER); /* Valid or Null */ 1997 LogFlowFunc (("pList=%p, pfSuccess=%p\n", 1998 pList, pfSuccess)); 1999 size_t cDevices = pList->size(); 2000 matchUSBDevice devHandler(pList); 2001 int rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", &devHandler); 2002 do { 2003 if (RT_FAILURE(rc)) 2004 break; 2005 for (USBDeviceInfoList::iterator pInfo = pList->begin(); 2006 pInfo != pList->end(); ++pInfo) 2007 { 2008 matchUSBInterface ifaceHandler(&*pInfo); 2009 rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", &ifaceHandler); 2010 if (RT_FAILURE(rc)) 2011 break; 2012 } 2013 } while(0); 2014 if (RT_FAILURE(rc)) 2015 /* Clean up again */ 2016 while (pList->size() > cDevices) 2017 pList->pop_back(); 2018 if (pfSuccess) 2019 *pfSuccess = RT_SUCCESS(rc); 2020 LogFlow (("rc=%Rrc\n", rc)); 2021 return rc; 2022 } 2023 1808 2024 1809 2025 /**
Note:
See TracChangeset
for help on using the changeset viewer.