- Timestamp:
- Jan 13, 2023 11:24:01 AM (2 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp
r96407 r98073 56 56 #ifdef VBOX_USB_WITH_SYSFS 57 57 # ifdef VBOX_USB_WITH_INOTIFY 58 # include <dlfcn.h> 59 # include <fcntl.h> 58 # include <fcntl.h> /* O_CLOEXEC */ 60 59 # include <poll.h> 61 60 # include <signal.h> 62 61 # include <unistd.h> 62 # include <sys/inotify.h> 63 63 # endif 64 64 #endif 65 65 66 #include <vector>66 //#include <vector> 67 67 68 68 #include <errno.h> … … 116 116 117 117 118 /** Find the length of a string, ignoring trailing non-ascii or control 118 /** 119 * Find the length of a string, ignoring trailing non-ascii or control 119 120 * characters 120 * @note Code duplicated in HostHardwareFreeBSD.cpp */ 121 * 122 * @note Code duplicated in HostHardwareFreeBSD.cpp 123 */ 121 124 static size_t strLenStripped(const char *pcsz) RT_NOTHROW_DEF 122 125 { … … 131 134 /** 132 135 * Get the name of a floppy drive according to the Linux floppy driver. 136 * 133 137 * @returns true on success, false if the name was not available (i.e. the 134 138 * device was not readable, or the file name wasn't a PC floppy … … 159 163 /** 160 164 * Create a UDI and a description for a floppy drive based on a number and the 161 * driver's name for it. We deliberately return an ugly sequence of 162 * characters as the description rather than an English language string to 163 * avoid translation issues. 165 * driver's name for it. 166 * 167 * We deliberately return an ugly sequence of characters as the description 168 * rather than an English language string to avoid translation issues. 164 169 * 165 170 * @returns true if we know the device to be valid, false otherwise … … 350 355 * Initialise the device strings (description and UDI) for a DVD drive based on 351 356 * vendor and model name strings. 357 * 352 358 * @param pcszVendor the vendor ID string 353 359 * @param pcszModel the product ID string … … 1018 1024 typedef struct inotifyWatch 1019 1025 { 1020 /** Pointer to the inotify_add_watch() glibc function/Linux API */1021 int (*inotify_add_watch)(int, const char *, uint32_t);1022 1026 /** The native handle of the inotify fd. */ 1023 1027 int mhInotify; … … 1026 1030 /** The flags we pass to inotify - modify, create, delete, change permissions 1027 1031 */ 1028 #define IN_FLAGS 0x306 1032 #define MY_IN_FLAGS (IN_CREATE | IN_DELETE | IN_MODIFY | IN_ATTRIB) 1033 AssertCompile(MY_IN_FLAGS == 0x306); 1029 1034 1030 1035 static int iwAddWatch(inotifyWatch *pSelf, const char *pcszPath) 1031 1036 { 1032 1037 errno = 0; 1033 if ( pSelf->inotify_add_watch(pSelf->mhInotify, pcszPath,IN_FLAGS) >= 01034 || (errno == EACCES))1038 if ( inotify_add_watch(pSelf->mhInotify, pcszPath, MY_IN_FLAGS) >= 0 1039 || errno == EACCES) 1035 1040 return VINF_SUCCESS; 1036 1041 /* Other errors listed in the manpage can be treated as fatal */ … … 1041 1046 static int iwInit(inotifyWatch *pSelf) 1042 1047 { 1043 int (*inotify_init)(void);1044 int fd, flags;1045 int rc = VINF_SUCCESS;1046 1047 1048 AssertPtr(pSelf); 1048 1049 pSelf->mhInotify = -1; 1049 errno = 0; 1050 *(void **)(&inotify_init) = dlsym(RTLD_DEFAULT, "inotify_init"); 1051 if (!inotify_init) 1052 return VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND; 1053 *(void **)(&pSelf->inotify_add_watch) 1054 = dlsym(RTLD_DEFAULT, "inotify_add_watch"); 1055 if (!pSelf->inotify_add_watch) 1056 return VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND; 1057 fd = inotify_init(); 1058 if (fd < 0) 1059 { 1060 Assert(errno > 0); 1061 return RTErrConvertFromErrno(errno); 1062 } 1063 Assert(errno == 0); 1064 1065 flags = fcntl(fd, F_GETFL, NULL); 1066 if ( flags < 0 1067 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0 1068 || fcntl(fd, F_SETFD, FD_CLOEXEC) < 0 /* race here */) 1069 { 1070 Assert(errno > 0); 1071 rc = RTErrConvertFromErrno(errno); 1072 } 1073 if (RT_FAILURE(rc)) 1074 close(fd); 1075 else 1076 { 1077 Assert(errno == 0); 1050 int fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK); 1051 if (fd >= 0) 1052 { 1078 1053 pSelf->mhInotify = fd; 1079 } 1080 return rc; 1054 return VINF_SUCCESS; 1055 } 1056 Assert(errno > 0); 1057 return RTErrConvertFromErrno(errno); 1081 1058 } 1082 1059 … … 1147 1124 /** Is inotify available and working on this system? If so we expect that 1148 1125 * this implementation will be usable. */ 1149 /** @todo test the "inotify in glibc but not in the kernel" case. */1150 1126 static bool Available(void) 1151 1127 { 1152 int (*inotify_init)(void); 1153 1154 *(void **)(&inotify_init) = dlsym(RTLD_DEFAULT, "inotify_init"); 1155 if (!inotify_init) 1156 return false; 1157 int fd = inotify_init(); 1158 if (fd == -1) 1159 return false; 1160 close(fd); 1161 return true; 1128 int const fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK); 1129 if (fd >= 0) 1130 close(fd); 1131 return fd >= 0; 1162 1132 } 1163 1133 … … 1181 1151 /* 1182 1152 * Create the pipe and set the close-on-exec flag. 1153 * ASSUMES we're building and running on Linux 2.6.27 or later (pipe2). 1183 1154 */ 1184 1155 int aFds[2] = {-1, -1}; 1185 if (pipe (aFds))1156 if (pipe2(aFds, O_CLOEXEC)) 1186 1157 return RTErrConvertFromErrno(errno); 1187 if ( fcntl(aFds[0], F_SETFD, FD_CLOEXEC) < 01188 || fcntl(aFds[1], F_SETFD, FD_CLOEXEC) < 0)1189 {1190 int rc = RTErrConvertFromErrno(errno);1191 close(aFds[0]);1192 close(aFds[1]);1193 return rc;1194 }1195 1158 1196 1159 *phPipeRead = aFds[0]; … … 1204 1167 } 1205 1168 1206 hotplugInotifyImpl::hotplugInotifyImpl(const char *pcszDevicesRoot) :1207 mhWakeupPipeR(-1), mhWakeupPipeW(-1), mfWaiting(0),1208 mpcszDevicesRoot(pcszDevicesRoot), mStatus(VERR_WRONG_ORDER)1169 hotplugInotifyImpl::hotplugInotifyImpl(const char *pcszDevicesRoot) 1170 : mhWakeupPipeR(-1), mhWakeupPipeW(-1), mfWaiting(0) 1171 , mpcszDevicesRoot(pcszDevicesRoot), mStatus(VERR_WRONG_ORDER) 1209 1172 { 1210 1173 # ifdef DEBUG … … 1217 1180 * available */ 1218 1181 # endif 1219 int rc; 1220 do { 1221 if (RT_FAILURE(rc = iwInit(&mWatches))) 1222 break; 1223 if (RT_FAILURE(rc = iwAddWatch(&mWatches, mpcszDevicesRoot))) 1224 break; 1225 if (RT_FAILURE(rc = pipeCreateSimple(&mhWakeupPipeR, &mhWakeupPipeW))) 1226 break; 1227 } while (0); 1182 1183 int rc = iwInit(&mWatches); 1184 if (RT_SUCCESS(rc)) 1185 { 1186 rc = iwAddWatch(&mWatches, mpcszDevicesRoot); 1187 if (RT_SUCCESS(rc)) 1188 rc = pipeCreateSimple(&mhWakeupPipeR, &mhWakeupPipeW); 1189 } 1228 1190 mStatus = rc; 1229 1191 if (RT_FAILURE(rc)) … … 1255 1217 AssertRCReturn(mStatus, VERR_WRONG_ORDER); 1256 1218 errno = 0; 1257 do {1219 do 1258 1220 cchRead = read(iwGetFD(&mWatches), chBuf, sizeof(chBuf)); 1259 }while (cchRead > 0);1221 while (cchRead > 0); 1260 1222 if (cchRead == 0) 1261 1223 return VINF_SUCCESS; … … 1286 1248 { 1287 1249 int rc; 1288 char **ppszEntry;1289 VECTOR_PTR(char *) vecpchDevs;1290 1250 1291 1251 AssertRCReturn(mStatus, VERR_WRONG_ORDER); 1292 1252 bool fEntered = ASMAtomicCmpXchgU32(&mfWaiting, 1, 0); 1293 1253 AssertReturn(fEntered, VERR_WRONG_ORDER); 1254 1255 VECTOR_PTR(char *) vecpchDevs; 1294 1256 VEC_INIT_PTR(&vecpchDevs, char *, RTStrFree); 1295 do { 1296 struct pollfd pollFD[MAX_POLLID]; 1297 1257 for (;;) 1258 { 1298 1259 rc = readFilePaths(mpcszDevicesRoot, &vecpchDevs, false); 1299 1260 if (RT_SUCCESS(rc)) 1261 { 1262 char **ppszEntry; 1300 1263 VEC_FOR_EACH(&vecpchDevs, char *, ppszEntry) 1301 1264 if (RT_FAILURE(rc = iwAddWatch(&mWatches, *ppszEntry))) 1302 1265 break; 1266 } 1303 1267 if (RT_FAILURE(rc)) 1304 1268 break; 1269 1270 struct pollfd pollFD[MAX_POLLID]; 1305 1271 pollFD[RPIPE_ID].fd = mhWakeupPipeR; 1306 1272 pollFD[RPIPE_ID].events = POLLIN; … … 1332 1298 if (RT_FAILURE(rc = drainInotify())) 1333 1299 break; 1334 } while (false); 1300 } 1301 1335 1302 mfWaiting = 0; 1336 1303 VEC_CLEANUP_PTR(&vecpchDevs);
Note:
See TracChangeset
for help on using the changeset viewer.