Changeset 31581 in vbox
- Timestamp:
- Aug 11, 2010 9:02:13 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/linux/HostHardwareLinux.cpp
r31564 r31581 90 90 91 91 /** Function object to be invoked on filenames from a directory. */ 92 classpathHandler92 typedef struct pathHandler 93 93 { 94 94 /** Called on each element of the sysfs directory. Can e.g. store 95 95 * interesting entries in a list. */ 96 virtual bool handle(const char *pcszNode) = 0; 97 public: 98 bool doHandle(const char *pcszNode) 99 { 100 AssertPtr(pcszNode); 101 Assert(pcszNode[0] == '/'); 102 return handle(pcszNode); 103 } 104 }; 96 bool (*handle)(pathHandler *pHandle, const char *pcszNode); 97 } pathHandler; 98 99 static bool phDoHandle(pathHandler *pHandler, const char *pcszNode) 100 { 101 AssertPtr(pHandler); 102 AssertPtr(pHandler->handle); 103 AssertPtr(pcszNode); 104 Assert(pcszNode[0] == '/'); 105 return pHandler->handle(pHandler, pcszNode); 106 } 105 107 106 108 static int walkDirectory(const char *pcszPath, pathHandler *pHandler, … … 1043 1045 * Inherits from pathHandler so that it can be passed to walkDirectory() to 1044 1046 * easily add all files from a directory. */ 1045 class inotifyWatch : public pathHandler 1046 { 1047 typedef struct inotifyWatch 1048 { 1049 /** The pathHandler we inherit from - this must be the first structure 1050 * member */ 1051 pathHandler mParent; 1047 1052 /** Pointer to the inotify_add_watch() glibc function/Linux API */ 1048 1053 int (*inotify_add_watch)(int, const char *, uint32_t); 1049 1054 /** The native handle of the inotify fd. */ 1050 1055 int mhInotify; 1051 /** Object initialisation status, to save us throwing an exception from 1052 * the constructor if we can't initialise */ 1053 int mStatus; 1054 1055 /** Object initialistation */ 1056 int initInotify(void); 1057 1058 public: 1059 /** Add @a pcszPath to the list of files and directories to be monitored */ 1060 virtual bool handle(const char *pcszPath); 1061 1062 inotifyWatch(void) : mhInotify(-1) 1063 { 1064 mStatus = initInotify(); 1065 } 1066 1067 ~inotifyWatch(void) 1068 { 1069 if (mhInotify != -1) 1070 { 1071 close(mhInotify); 1072 mhInotify = -1; 1073 } 1074 } 1075 1076 int getStatus(void) 1077 { 1078 return mStatus; 1079 } 1080 1081 int getFD(void) 1082 { 1083 AssertRCReturn(mStatus, -1); 1084 return mhInotify; 1085 } 1086 }; 1087 1088 int inotifyWatch::initInotify(void) 1056 } inotifyWatch; 1057 1058 /** The flags we pass to inotify - modify, create, delete, change permissions 1059 */ 1060 #define IN_FLAGS 0x306 1061 1062 static bool iwHandle(pathHandler *pParent, const char *pcszPath) 1063 { 1064 AssertPtrReturn(pParent, false); 1065 AssertReturn(pParent->handle == iwHandle, false); 1066 inotifyWatch *pSelf = (inotifyWatch *)pParent; 1067 errno = 0; 1068 if ( pSelf->inotify_add_watch(pSelf->mhInotify, pcszPath, IN_FLAGS) >= 0 1069 || (errno == EACCES)) 1070 return true; 1071 /* Other errors listed in the manpage can be treated as fatal */ 1072 return false; 1073 } 1074 1075 /** Object initialisation */ 1076 static int iwInit(inotifyWatch *pSelf) 1089 1077 { 1090 1078 int (*inotify_init)(void); 1091 1079 int fd, flags; 1092 1080 int rc = VINF_SUCCESS; 1081 1082 AssertPtr(pSelf); 1083 pSelf->mParent.handle = iwHandle; 1084 pSelf->mhInotify = -1; 1093 1085 errno = 0; 1094 1086 *(void **)(&inotify_init) = dlsym(RTLD_DEFAULT, "inotify_init"); 1095 1087 if (!inotify_init) 1096 1088 return VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND; 1097 *(void **)(&inotify_add_watch) = dlsym(RTLD_DEFAULT, "inotify_add_watch"); 1098 if (!inotify_add_watch) 1089 *(void **)(&pSelf->inotify_add_watch) 1090 = dlsym(RTLD_DEFAULT, "inotify_add_watch"); 1091 if (!pSelf->inotify_add_watch) 1099 1092 return VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND; 1100 1093 fd = inotify_init(); … … 1106 1099 Assert(errno == 0); 1107 1100 1108 int rc = VINF_SUCCESS;1109 1110 1101 flags = fcntl(fd, F_GETFL, NULL); 1111 1102 if ( flags < 0 … … 1120 1111 { 1121 1112 Assert(errno == 0); 1122 mhInotify = fd;1113 pSelf->mhInotify = fd; 1123 1114 } 1124 1115 return rc; 1125 1116 } 1126 1117 1127 /** The flags we pass to inotify - modify, create, delete, change permissions 1128 */ 1129 #define IN_FLAGS 0x306 1130 1131 bool inotifyWatch::handle(const char *pcszPath) 1132 { 1133 AssertRCReturn(mStatus, false); 1134 errno = 0; 1135 if ( inotify_add_watch(mhInotify, pcszPath, IN_FLAGS) >= 0 1136 || (errno == EACCES)) 1137 return true; 1138 /* Other errors listed in the manpage can be treated as fatal */ 1139 return false; 1118 static void iwTerm(inotifyWatch *pSelf) 1119 { 1120 AssertPtrReturnVoid(pSelf); 1121 if (pSelf->mhInotify != -1) 1122 { 1123 close(pSelf->mhInotify); 1124 pSelf->mhInotify = -1; 1125 } 1126 } 1127 1128 static int iwGetFD(inotifyWatch *pSelf) 1129 { 1130 AssertPtrReturn(pSelf, -1); 1131 return pSelf->mhInotify; 1140 1132 } 1141 1133 … … 1243 1235 int rc; 1244 1236 do { 1245 if (RT_FAILURE(rc = mWatches.getStatus()))1237 if (RT_FAILURE(rc = iwInit(&mWatches))) 1246 1238 break; 1247 mWatches.doHandle(SYSFS_USB_DEVICE_PATH);1239 phDoHandle(&mWatches.mParent, SYSFS_USB_DEVICE_PATH); 1248 1240 if (RT_FAILURE(rc = pipeCreateSimple(&mhWakeupPipeR, &mhWakeupPipeW))) 1249 1241 break; … … 1268 1260 mhWakeupPipeW = -1; 1269 1261 } 1262 iwTerm(&mWatches); 1270 1263 } 1271 1264 … … 1278 1271 errno = 0; 1279 1272 do { 1280 cchRead = read( mWatches.getFD(), chBuf, sizeof(chBuf));1273 cchRead = read(iwGetFD(&mWatches), chBuf, sizeof(chBuf)); 1281 1274 } while (cchRead > 0); 1282 1275 if (cchRead == 0) … … 1309 1302 struct pollfd pollFD[MAX_POLLID]; 1310 1303 1311 if (RT_FAILURE(rc = walkDirectory(SYSFS_USB_DEVICE_PATH, &mWatches ,1304 if (RT_FAILURE(rc = walkDirectory(SYSFS_USB_DEVICE_PATH, &mWatches.mParent, 1312 1305 false))) 1313 1306 break; 1314 1307 pollFD[RPIPE_ID].fd = mhWakeupPipeR; 1315 1308 pollFD[RPIPE_ID].events = POLLIN; 1316 pollFD[INOTIFY_ID].fd = mWatches.getFD();1309 pollFD[INOTIFY_ID].fd = iwGetFD(&mWatches); 1317 1310 pollFD[INOTIFY_ID].events = POLLIN | POLLERR | POLLHUP; 1318 1311 errno = 0; … … 1424 1417 if (RT_FAILURE(rc)) 1425 1418 break; /* The file can vanish if a device is unplugged. */ 1426 if (!p Handler->doHandle(szAbsPath))1419 if (!phDoHandle(pHandler, szAbsPath)) 1427 1420 break; 1428 1421 } 1429 1422 else 1430 if (!p Handler->doHandle(szPath))1423 if (!phDoHandle(pHandler, szPath)) 1431 1424 break; 1432 1425 } … … 1482 1475 * interface. To be used with getDeviceInfoFromSysfs(). 1483 1476 */ 1484 class matchUSBDevice : public pathHandler 1485 { 1477 typedef struct matchUSBDevice 1478 { 1479 /** The pathHandler object we inherit from - must come first */ 1480 pathHandler mParent; 1486 1481 USBDeviceInfoList *mList; 1487 public: 1488 matchUSBDevice(USBDeviceInfoList *pList) : mList(pList) {} 1489 private: 1490 virtual bool handle(const char *pcszNode) 1491 { 1492 const char *pcszFile = strrchr(pcszNode, '/'); 1493 if (strchr(pcszFile, ':')) 1494 return true; 1495 dev_t devnum = RTLinuxSysFsReadDevNumFile("%s/dev", pcszNode); 1496 /* Sanity test of our static helpers */ 1497 Assert(usbBusFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 5); 1498 Assert(usbDeviceFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 6); 1499 AssertReturn (devnum, true); 1500 char szDevPath[RTPATH_MAX]; 1501 ssize_t cchDevPath; 1502 cchDevPath = RTLinuxFindDevicePath(devnum, RTFS_TYPE_DEV_CHAR, 1503 szDevPath, sizeof(szDevPath), 1504 "/dev/bus/usb/%.3d/%.3d", 1505 usbBusFromDevNum(devnum), 1506 usbDeviceFromDevNum(devnum)); 1507 if (cchDevPath < 0) 1508 return true; 1509 try 1510 { 1511 mList->push_back(USBDeviceInfo(szDevPath, pcszNode)); 1512 } 1513 catch(std::bad_alloc &e) 1514 { 1515 return false; 1516 } 1517 return true; 1518 } 1519 }; 1482 } matchUSBDevice; 1483 1484 static bool mudHandle(pathHandler *pParent, const char *pcszNode) 1485 { 1486 AssertPtrReturn(pParent, false); 1487 AssertReturn(pParent->handle = mudHandle, false); 1488 matchUSBDevice *pSelf = (matchUSBDevice *)pParent; 1489 const char *pcszFile = strrchr(pcszNode, '/'); 1490 if (strchr(pcszFile, ':')) 1491 return true; 1492 dev_t devnum = RTLinuxSysFsReadDevNumFile("%s/dev", pcszNode); 1493 /* Sanity test of our static helpers */ 1494 Assert(usbBusFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 5); 1495 Assert(usbDeviceFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 6); 1496 AssertReturn (devnum, true); 1497 char szDevPath[RTPATH_MAX]; 1498 ssize_t cchDevPath; 1499 cchDevPath = RTLinuxFindDevicePath(devnum, RTFS_TYPE_DEV_CHAR, 1500 szDevPath, sizeof(szDevPath), 1501 "/dev/bus/usb/%.3d/%.3d", 1502 usbBusFromDevNum(devnum), 1503 usbDeviceFromDevNum(devnum)); 1504 if (cchDevPath < 0) 1505 return true; 1506 try 1507 { 1508 pSelf->mList->push_back(USBDeviceInfo(szDevPath, pcszNode)); 1509 } 1510 catch(std::bad_alloc &e) 1511 { 1512 return false; 1513 } 1514 return true; 1515 } 1516 1517 static void mudInit(matchUSBDevice *pSelf, USBDeviceInfoList *pList) 1518 { 1519 AssertPtrReturnVoid(pSelf); 1520 pSelf->mParent.handle = mudHandle; 1521 pSelf->mList = pList; 1522 } 1523 1520 1524 1521 1525 /** … … 1523 1527 * device. To be used with getDeviceInfoFromSysfs(). 1524 1528 */ 1525 class matchUSBInterface : public pathHandler 1526 { 1529 typedef struct matchUSBInterface 1530 { 1531 /** The pathHandler class we inherit from - must be the first member. */ 1532 pathHandler mParent; 1527 1533 USBDeviceInfo *mInfo; 1528 public: 1529 /** This constructor is currently used to unit test the class logic in 1530 * debug builds. Since no access is made to anything outside the class, 1531 * this shouldn't cause any slowdown worth mentioning. */ 1532 matchUSBInterface(USBDeviceInfo *pInfo) : mInfo(pInfo) 1533 { 1534 Assert(isAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0", 1535 "/sys/devices/pci0000:00/0000:00:1a.0/usb3")); 1536 Assert(!isAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-1", 1537 "/sys/devices/pci0000:00/0000:00:1a.0/usb3")); 1538 Assert(!isAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/driver", 1539 "/sys/devices/pci0000:00/0000:00:1a.0/usb3")); 1540 } 1541 private: 1542 /** The logic for testing whether a sysfs address corresponds to an 1543 * interface of a device. Both must be referenced by their canonical 1544 * sysfs paths. This is not tested, as the test requires file-system 1545 * interaction. */ 1546 bool isAnInterfaceOf(const char *pcszIface, const char *pcszDev) 1547 { 1548 size_t cchDev = strlen(pcszDev); 1549 1550 AssertPtr(pcszIface); 1551 AssertPtr(pcszDev); 1552 Assert(pcszIface[0] == '/'); 1553 Assert(pcszDev[0] == '/'); 1554 Assert(pcszDev[cchDev - 1] != '/'); 1555 /* If this passes, pcszIface is at least cchDev long */ 1556 if (strncmp(pcszIface, pcszDev, cchDev)) 1557 return false; 1558 /* If this passes, pcszIface is longer than cchDev */ 1559 if (pcszIface[cchDev] != '/') 1560 return false; 1561 /* In sysfs an interface is an immediate subdirectory of the device */ 1562 if (strchr(pcszIface + cchDev + 1, '/')) 1563 return false; 1564 /* And it always has a colon in its name */ 1565 if (!strchr(pcszIface + cchDev + 1, ':')) 1566 return false; 1567 /* And hopefully we have now elimitated everything else */ 1568 return true; 1569 } 1570 1571 virtual bool handle(const char *pcszNode) 1572 { 1573 if (!isAnInterfaceOf(pcszNode, mInfo->mSysfsPath.c_str())) 1574 return true; 1575 try 1576 { 1577 mInfo->mInterfaces.push_back(pcszNode); 1578 } 1579 catch(std::bad_alloc &e) 1580 { 1581 return false; 1582 } 1583 return true; 1584 } 1585 }; 1534 } matchUSBInterface; 1535 1536 /** The logic for testing whether a sysfs address corresponds to an 1537 * interface of a device. Both must be referenced by their canonical 1538 * sysfs paths. This is not tested, as the test requires file-system 1539 * interaction. */ 1540 static bool muiIsAnInterfaceOf(const char *pcszIface, const char *pcszDev) 1541 { 1542 size_t cchDev = strlen(pcszDev); 1543 1544 AssertPtr(pcszIface); 1545 AssertPtr(pcszDev); 1546 Assert(pcszIface[0] == '/'); 1547 Assert(pcszDev[0] == '/'); 1548 Assert(pcszDev[cchDev - 1] != '/'); 1549 /* If this passes, pcszIface is at least cchDev long */ 1550 if (strncmp(pcszIface, pcszDev, cchDev)) 1551 return false; 1552 /* If this passes, pcszIface is longer than cchDev */ 1553 if (pcszIface[cchDev] != '/') 1554 return false; 1555 /* In sysfs an interface is an immediate subdirectory of the device */ 1556 if (strchr(pcszIface + cchDev + 1, '/')) 1557 return false; 1558 /* And it always has a colon in its name */ 1559 if (!strchr(pcszIface + cchDev + 1, ':')) 1560 return false; 1561 /* And hopefully we have now elimitated everything else */ 1562 return true; 1563 } 1564 1565 static bool muiHandle(pathHandler *pParent, const char *pcszNode) 1566 { 1567 AssertPtrReturn(pParent, false); 1568 AssertReturn(pParent->handle == muiHandle, false); 1569 matchUSBInterface *pSelf = (matchUSBInterface *)pParent; 1570 if (!muiIsAnInterfaceOf(pcszNode, pSelf->mInfo->mSysfsPath.c_str())) 1571 return true; 1572 try 1573 { 1574 pSelf->mInfo->mInterfaces.push_back(pcszNode); 1575 } 1576 catch(std::bad_alloc &e) 1577 { 1578 return false; 1579 } 1580 return true; 1581 } 1582 1583 /** This constructor is currently used to unit test the class logic in 1584 * debug builds. Since no access is made to anything outside the class, 1585 * this shouldn't cause any slowdown worth mentioning. */ 1586 static void muiInit(matchUSBInterface *pSelf, USBDeviceInfo *pInfo) 1587 { 1588 Assert(muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0", 1589 "/sys/devices/pci0000:00/0000:00:1a.0/usb3")); 1590 Assert(!muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-1", 1591 "/sys/devices/pci0000:00/0000:00:1a.0/usb3")); 1592 Assert(!muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/driver", 1593 "/sys/devices/pci0000:00/0000:00:1a.0/usb3")); 1594 AssertPtrReturnVoid(pSelf); 1595 pSelf->mInfo = pInfo; 1596 pSelf->mParent.handle = muiHandle; 1597 } 1586 1598 1587 1599 /** … … 1602 1614 pList, pfSuccess)); 1603 1615 size_t cDevices = pList->size(); 1604 matchUSBDevice devHandler(pList); 1605 int rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", &devHandler); 1616 matchUSBDevice devHandler; 1617 mudInit(&devHandler, pList); 1618 int rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", &devHandler.mParent); 1606 1619 do { 1607 1620 if (RT_FAILURE(rc)) … … 1610 1623 pInfo != pList->end(); ++pInfo) 1611 1624 { 1612 matchUSBInterface ifaceHandler(&*pInfo); 1613 rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", &ifaceHandler); 1625 matchUSBInterface ifaceHandler; 1626 muiInit(&ifaceHandler, &*pInfo); 1627 rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", 1628 &ifaceHandler.mParent); 1614 1629 if (RT_FAILURE(rc)) 1615 1630 break;
Note:
See TracChangeset
for help on using the changeset viewer.