VirtualBox

Changeset 28309 in vbox


Ignore:
Timestamp:
Apr 14, 2010 3:22:16 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
60067
Message:

Main/HostHardwareLinux: added code for querying USB device information straight from sysfs

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/linux/HostHardwareLinux.cpp

    r26296 r28309  
    9393static int getDriveInfoFromSysfs(DriveInfoList *pList, bool isDVD,
    9494                                 bool *pfSuccess);
     95static int getUSBDeviceInfoFromSysfs(USBDeviceInfoList *pList, bool *pfSuccess);
    9596#ifdef VBOX_WITH_DBUS
    9697/* These must be extern to be usable in the RTMemAutoPtr template */
     
    10391040            success = halSuccess;
    10401041#endif /* VBOX_WITH_DBUS defined */
     1042        if (   RT_SUCCESS(rc)
     1043            && (!success || testing()))
     1044            rc = getUSBDeviceInfoFromSysfs(&mDeviceList, &halSuccess);
    10411045#endif /* RT_OS_LINUX */
    10421046    }
     
    18061810    return rc;
    18071811}
     1812
     1813class 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;
     1818public:
     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 */
     1839int 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 */
     1883class matchUSBDevice : public sysfsPathHandler
     1884{
     1885    USBDeviceInfoList *mList;
     1886public:
     1887    matchUSBDevice(USBDeviceInfoList *pList) : mList(pList) {}
     1888private:
     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 */
     1921class matchUSBInterface : public sysfsPathHandler
     1922{
     1923    USBDeviceInfo *mInfo;
     1924public:
     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    }
     1937private:
     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 */
     1992static 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
    18082024
    18092025/**
Note: See TracChangeset for help on using the changeset viewer.

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