diff options
Diffstat (limited to 'src/VBox/Main/src-server/linux/USBGetDevices.cpp')
-rw-r--r-- | src/VBox/Main/src-server/linux/USBGetDevices.cpp | 144 |
1 files changed, 109 insertions, 35 deletions
diff --git a/src/VBox/Main/src-server/linux/USBGetDevices.cpp b/src/VBox/Main/src-server/linux/USBGetDevices.cpp index b2e2b70b3..02e684aa0 100644 --- a/src/VBox/Main/src-server/linux/USBGetDevices.cpp +++ b/src/VBox/Main/src-server/linux/USBGetDevices.cpp @@ -94,15 +94,6 @@ static const USBSUFF s_aIntervalSuff[] = { "", 0, 0, 0 } /* term */ }; -/** - * List of well-known USB device tree locations. - */ -static const USBDEVTREELOCATION s_aTreeLocations[] = -{ - { "/dev/vboxusb", true }, - { "/proc/bus/usb", false }, -}; - /** * "reads" the number suffix. It's more like validating it and @@ -1398,9 +1389,36 @@ static PUSBDEVICE getDevicesFromSysfs(const char *pcszDevicesRoot, bool testfs) #endif /* !VBOX_USB_WITH_SYSFS */ } +#ifdef UNIT_TEST +/* Set up mock functions for USBProxyLinuxCheckDeviceRoot - here dlsym and close + * for the inotify presence check. */ +static int testInotifyInitGood(void) { return 0; } +static int testInotifyInitBad(void) { return -1; } +static bool s_fHaveInotifyLibC = true; +static bool s_fHaveInotifyKernel = true; + +static void *testDLSym(void *handle, const char *symbol) +{ + Assert(handle == RTLD_DEFAULT); + Assert(!RTStrCmp(symbol, "inotify_init")); + if (!s_fHaveInotifyLibC) + return NULL; + if (s_fHaveInotifyKernel) + return (void *)testInotifyInitGood; + return (void *)testInotifyInitBad; +} + +void TestUSBSetInotifyAvailable(bool fHaveInotifyLibC, bool fHaveInotifyKernel) +{ + s_fHaveInotifyLibC = fHaveInotifyLibC; + s_fHaveInotifyKernel = fHaveInotifyKernel; +} +# define dlsym testDLSym +# define close(a) do {} while(0) +#endif + /** Is inotify available and working on this system? This is a requirement * for using USB with sysfs */ -/** @todo test the "inotify in glibc but not in the kernel" case. */ static bool inotifyAvailable(void) { int (*inotify_init)(void); @@ -1415,40 +1433,96 @@ static bool inotifyAvailable(void) return true; } -PCUSBDEVTREELOCATION USBProxyLinuxGetDeviceRoot(bool fPreferSysfs) +#ifdef UNIT_TEST +# undef dlsym +# undef close +#endif + +#ifdef UNIT_TEST +/** Unit test list of usbfs addresses of connected devices. */ +static const char **s_pacszUsbfsDeviceAddresses = NULL; + +static PUSBDEVICE testGetUsbfsDevices(const char *pcszUsbfsRoot, bool testfs) +{ + const char **pcsz; + PUSBDEVICE pList = NULL, pTail = NULL; + for (pcsz = s_pacszUsbfsDeviceAddresses; pcsz && *pcsz; ++pcsz) + { + PUSBDEVICE pNext = (PUSBDEVICE)RTMemAllocZ(sizeof(USBDEVICE)); + if (pNext) + pNext->pszAddress = RTStrDup(*pcsz); + if (!pNext || !pNext->pszAddress) + { + deviceListFree(&pList); + return NULL; + } + if (pTail) + pTail->pNext = pNext; + else + pList = pNext; + pTail = pNext; + } + return pList; +} +# define getDevicesFromUsbfs testGetUsbfsDevices + +void TestUSBSetAvailableUsbfsDevices(const char **pacszDeviceAddresses) +{ + s_pacszUsbfsDeviceAddresses = pacszDeviceAddresses; +} + +/** Unit test list of files reported as accessible by access(3). We only do + * accessible or not accessible. */ +static const char **s_pacszAccessibleFiles = NULL; + +static int testAccess(const char *pcszPath, int mode) +{ + const char **pcsz; + for (pcsz = s_pacszAccessibleFiles; pcsz && *pcsz; ++pcsz) + if (!RTStrCmp(pcszPath, *pcsz)) + return 0; + return -1; +} +# define access testAccess + +void TestUSBSetAccessibleFiles(const char **pacszAccessibleFiles) +{ + s_pacszAccessibleFiles = pacszAccessibleFiles; +} +#endif + +bool USBProxyLinuxCheckDeviceRoot(const char *pcszRoot, bool fIsDeviceNodes) { - PCUSBDEVTREELOCATION pcBestUsbfs = NULL; - PCUSBDEVTREELOCATION pcBestSysfs = NULL; + bool fOK = false; + if (!fIsDeviceNodes) /* usbfs */ + { + PUSBDEVICE pDevices; - bool fHaveInotify = inotifyAvailable(); - for (unsigned i = 0; i < RT_ELEMENTS(s_aTreeLocations); ++i) - if (!s_aTreeLocations[i].fUseSysfs) + if (!access(pcszRoot, R_OK | X_OK)) { - if (!pcBestUsbfs) + fOK = true; + pDevices = getDevicesFromUsbfs(pcszRoot, true); + if (pDevices) { - PUSBDEVICE pDevices; + PUSBDEVICE pDevice; - pDevices = getDevicesFromUsbfs(s_aTreeLocations[i].szDevicesRoot, - true); - if (pDevices) - { - pcBestUsbfs = &s_aTreeLocations[i]; - deviceListFree(&pDevices); - } + for (pDevice = pDevices; pDevice && fOK; pDevice = pDevice->pNext) + if (access(pDevice->pszAddress, R_OK | W_OK)) + fOK = false; + deviceListFree(&pDevices); } } - else - { - if ( fHaveInotify - && !pcBestSysfs - && RTPathExists(s_aTreeLocations[i].szDevicesRoot)) - pcBestSysfs = &s_aTreeLocations[i]; - } - if (pcBestUsbfs && !fPreferSysfs) - return pcBestUsbfs; - return pcBestSysfs; + } + else /* device nodes */ + if (inotifyAvailable() && !access(pcszRoot, R_OK | X_OK)) + fOK = true; + return fOK; } +#ifdef UNIT_TEST +# undef getDevicesFromUsbfs +# undef access +#endif PUSBDEVICE USBProxyLinuxGetDevices(const char *pcszDevicesRoot, bool fUseSysfs) |