- Timestamp:
- Sep 24, 2009 7:44:27 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/linux/sysfs.h
r20374 r23309 36 36 #include <iprt/stdarg.h> 37 37 38 #include <sys/types.h> 38 39 39 40 RT_C_DECLS_BEGIN … … 119 120 120 121 /** 122 * Reads a device number from a sysfs file. 123 * 124 * @returns device number on success, 0 and errno on failure. 125 * @param pszFormat The filename format, either absolute or relative to "/sys/". 126 * @param va Format args. 127 */ 128 RTDECL(dev_t) RTLinuxSysFsReadDevNumFileV(const char *pszFormat, va_list va); 129 130 /** 131 * Reads a device number from a sysfs file. 132 * 133 * @returns device number on success, 0 and errno on failure. 134 * @param pszFormat The filename format, either absolute or relative to "/sys/". 135 * @param ... Format args. 136 */ 137 RTDECL(dev_t) RTLinuxSysFsReadDevNumFile(const char *pszFormat, ...); 138 139 /** 121 140 * Reads a string from a sysfs file. If the file contains a newline, we only 122 141 * return the text up until there. … … 178 197 RTDECL(ssize_t) RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, const char *pszFormat, ...); 179 198 199 /** 200 * Find the path of a device node under /dev, given then device number. This 201 * function will recursively search under /dev until it finds a device node 202 * matching @a devnum, and store the path into @a pszBuf. The caller may 203 * provide an expected path in pszSuggestion, which will be tried before 204 * searching, but due to the variance in Linux systems it can be hard to always 205 * correctly predict the path. 206 * 207 * @returns the number of characters written on success, -1 and errno on 208 * failure 209 * @returns -1 and ENOENT if no matching device node could be found 210 * @param devNum the device number to search for 211 * @param fMode the type of device - only RTFS_TYPE_DEV_CHAR 212 * and RTFS_TYPE_DEV_BLOCK are valid values 213 * @param pszBuf where to store the path 214 * @param cchBuf the size of the buffer 215 * @param pszSuggestion the expected path format of the device node, either 216 * absolute or relative to "/dev" (optional) 217 * @param va Format args. 218 */ 219 RTDECL(ssize_t) RTLinuxFindDevicePathV(dev_t devNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, const char *pszSuggestion, va_list va); 220 221 /** 222 * Find the path of a device node under /dev, given then device number. This 223 * function will recursively search under /dev until it finds a device node 224 * matching @a devnum, and store the path into @a pszBuf. The caller may 225 * provide an expected path in pszSuggestion, which will be tried before 226 * searching, but due to the variance in Linux systems it can be hard to always 227 * correctly predict the path. 228 * 229 * @returns the number of characters written on success, -1 and errno on 230 * failure 231 * @returns -1 and ENOENT if no matching device node could be found 232 * @param devNum the device number to search for 233 * @param fMode the type of device - only RTFS_TYPE_DEV_CHAR 234 * and RTFS_TYPE_DEV_BLOCK are valid values 235 * @param pszBuf where to store the path 236 * @param cchBuf the size of the buffer 237 * @param pszSuggestion the expected path format of the device node, either 238 * absolute or relative to "/dev" (optional) 239 * @param ... Format args. 240 */ 241 RTDECL(ssize_t) RTLinuxFindDevicePath(dev_t devNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, const char *pszSuggestion, ...); 242 180 243 /** @} */ 181 244 -
trunk/src/VBox/Runtime/r3/linux/sysfs.cpp
r15644 r23309 36 36 #include <iprt/linux/sysfs.h> 37 37 #include <iprt/assert.h> 38 #include <iprt/dir.h> 39 #include <iprt/err.h> 40 #include <iprt/fs.h> 38 41 #include <iprt/param.h> 39 42 #include <iprt/path.h> … … 46 49 #include <sys/fcntl.h> 47 50 #include <errno.h> 51 52 53 /** 54 * Constructs the path of a sysfs file from the format paramaters passed, 55 * prepending a prefix if the path is relative. 56 * 57 * @returns The number of characters returned, or -1 and errno set to ERANGE on 58 * failure. 59 * 60 * @param pszPrefix The prefix to prepend if the path is relative. Must end 61 * in '/'. 62 * @param pszBuf Where to write the path. Must be at least 63 * sizeof(@a pszPrefix) characters long 64 * @param cchBuf The size of the buffer pointed to by @a pszBuf. 65 * @param pszFormat The name format, either absolute or relative to "/sys/". 66 * @param va The format args. 67 */ 68 static ssize_t rtLinuxConstructPathV(char *pszBuf, size_t cchBuf, 69 const char *pszPrefix, 70 const char *pszFormat, va_list va) 71 { 72 size_t cchPrefix = strlen(pszPrefix); 73 AssertReturnStmt(pszPrefix[cchPrefix - 1] == '/', errno = ERANGE, -1); 74 AssertReturnStmt(cchBuf > cchPrefix + 1, errno = ERANGE, -1); 75 76 size_t cch = RTStrPrintfV(pszBuf, cchBuf, pszFormat, va); 77 if (*pszBuf != '/') 78 { 79 AssertReturnStmt(cchBuf >= cch + cchPrefix + 1, errno = ERANGE, -1); 80 memmove(pszBuf + cchPrefix, pszBuf, cch + 1); 81 memcpy(pszBuf, pszPrefix, cchPrefix); 82 cch += cchPrefix; 83 } 84 return cch; 85 } 86 87 88 /** 89 * Constructs the path of a sysfs file from the format paramaters passed, 90 * prepending a prefix if the path is relative. 91 * 92 * @returns The number of characters returned, or -1 and errno set to ERANGE on 93 * failure. 94 * 95 * @param pszPrefix The prefix to prepend if the path is relative. Must end 96 * in '/'. 97 * @param pszBuf Where to write the path. Must be at least 98 * sizeof(@a pszPrefix) characters long 99 * @param cchBuf The size of the buffer pointed to by @a pszBuf. 100 * @param pszFormat The name format, either absolute or relative to "/sys/". 101 * @param ... The format args. 102 */ 103 static ssize_t rtLinuxConstructPath(char *pszBuf, size_t cchBuf, 104 const char *pszPrefix, 105 const char *pszFormat, ...) 106 { 107 va_list va; 108 va_start(va, pszFormat); 109 int rc = rtLinuxConstructPathV(pszBuf, cchBuf, pszPrefix, pszFormat, va); 110 va_end(va); 111 return rc; 112 } 48 113 49 114 … … 63 128 static ssize_t rtLinuxSysFsConstructPath(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va) 64 129 { 65 static const char s_szPrefix[] = "/sys/"; 66 AssertReturnStmt(cchBuf > sizeof(s_szPrefix), errno = ERANGE, -1); 67 68 size_t cch = RTStrPrintfV(pszBuf, cchBuf, pszFormat, va); 69 if (*pszBuf != '/') 70 { 71 AssertReturnStmt(cchBuf >= cch + sizeof(s_szPrefix), errno = ERANGE, -1); 72 memmove(pszBuf + sizeof(s_szPrefix) - 1, pszBuf, cch + 1); 73 memcpy(pszBuf, s_szPrefix, sizeof(s_szPrefix) - 1); 74 cch += sizeof(s_szPrefix) - 1; 75 } 76 return cch; 130 return rtLinuxConstructPathV(pszBuf, cchBuf, "/sys/", pszFormat, va); 77 131 } 78 132 … … 185 239 186 240 241 RTDECL(dev_t) RTLinuxSysFsReadDevNumFileV(const char *pszFormat, va_list va) 242 { 243 int fd = RTLinuxSysFsOpenV(pszFormat, va); 244 if (fd == -1) 245 return 0; 246 247 dev_t devNum = 0; 248 char szNum[128]; 249 ssize_t cchNum = RTLinuxSysFsReadStr(fd, szNum, sizeof(szNum)); 250 if (cchNum > 0) 251 { 252 uint32_t u32Maj = 0; 253 uint32_t u32Min = 0; 254 char *pszNext = NULL; 255 int rc = RTStrToUInt32Ex(szNum, &pszNext, 10, &u32Maj); 256 if (RT_FAILURE(rc) || (rc != VWRN_TRAILING_CHARS) || (*pszNext != ':')) 257 errno = EINVAL; 258 else 259 { 260 rc = RTStrToUInt32Ex(pszNext + 1, NULL, 10, &u32Min); 261 if ( rc != VINF_SUCCESS 262 && rc != VWRN_TRAILING_CHARS 263 && rc != VWRN_TRAILING_SPACES) 264 errno = EINVAL; 265 else 266 { 267 errno = 0; 268 devNum = makedev(u32Maj, u32Min); 269 } 270 } 271 } 272 else if (cchNum == 0) 273 errno = EINVAL; 274 275 RTLinuxSysFsClose(fd); 276 return devNum; 277 } 278 279 280 RTDECL(dev_t) RTLinuxSysFsReadDevNumFile(const char *pszFormat, ...) 281 { 282 va_list va; 283 va_start(va, pszFormat); 284 dev_t devNum = RTLinuxSysFsReadDevNumFileV(pszFormat, va); 285 va_end(va); 286 return devNum; 287 } 288 289 187 290 RTDECL(ssize_t) RTLinuxSysFsReadStrFileV(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va) 188 291 { … … 269 372 } 270 373 374 375 static ssize_t rtLinuxFindDevicePathRecursive(dev_t devNum, RTFMODE fMode, 376 const char *pszBasePath, 377 char *pszBuf, size_t cchBuf) 378 { 379 PRTDIR pDir = NULL; 380 RTDIRENTRYEX entry = { {0} }; 381 int vrc = VINF_SUCCESS; 382 ssize_t rc; 383 384 vrc = RTDirOpen(&pDir, pszBasePath); 385 if (RT_SUCCESS(vrc)) 386 while (true) 387 { 388 vrc = RTDirReadEx(pDir, &entry, NULL, RTFSOBJATTRADD_UNIX); 389 if (RT_FAILURE(vrc)) 390 { 391 errno = (vrc == VERR_NO_MORE_FILES) ? ENOENT 392 : (vrc == VERR_BUFFER_OVERFLOW) ? EOVERFLOW 393 : EIO; 394 rc = -1; 395 break; 396 } 397 if (RTFS_IS_SYMLINK(entry.Info.Attr.fMode)) 398 continue; 399 if ( (entry.Info.Attr.u.Unix.Device == devNum) 400 && ( ( (fMode == RTFS_TYPE_DEV_CHAR) 401 && RTFS_IS_DEV_CHAR(entry.Info.Attr.fMode)) 402 || ( (fMode == RTFS_TYPE_DEV_BLOCK) 403 && RTFS_IS_DEV_BLOCK(entry.Info.Attr.fMode)))) 404 { 405 rc = rtLinuxConstructPath(pszBuf, cchBuf, pszBasePath, "%s", 406 entry.szName); 407 break; 408 } 409 if (!RTFS_IS_DIRECTORY(entry.Info.Attr.fMode)) 410 continue; 411 if (entry.szName[0] == '.') 412 continue; 413 char szPath[RTPATH_MAX]; 414 /** @todo this is a temporary hack, as RTDirReadEx currently 415 * doesn't know about symbolic links */ 416 rc = rtLinuxConstructPath(szPath, sizeof(szPath), pszBasePath, 417 "%s", entry.szName); 418 if (rc < 0) 419 break; 420 struct stat Stat = { 0 }; 421 if ( lstat(szPath, &Stat) < 0 422 || S_ISLNK(Stat.st_mode)) 423 continue; 424 /* @todo ends here */ 425 rc = rtLinuxConstructPath(szPath, sizeof(szPath), pszBasePath, 426 "%s/", entry.szName); 427 if (rc < 0) 428 break; 429 rc = rtLinuxFindDevicePathRecursive(devNum, fMode, szPath, 430 pszBuf, cchBuf); 431 if ((rc >= 0) || errno != ENOENT) 432 break; 433 } 434 else 435 { 436 rc = -1; 437 errno = RTErrConvertToErrno(vrc); 438 } 439 RTDirClose(pDir); 440 return rc; 441 } 442 443 444 RTDECL(ssize_t) RTLinuxFindDevicePathV(dev_t devNum, RTFMODE fMode, 445 char *pszBuf, size_t cchBuf, 446 const char *pszSuggestion, va_list va) 447 { 448 AssertReturnStmt(cchBuf >= 2, errno = EINVAL, -1); 449 AssertReturnStmt( (fMode == RTFS_TYPE_DEV_CHAR) 450 || (fMode == RTFS_TYPE_DEV_BLOCK), 451 errno = EINVAL, -1); 452 453 if (!pszSuggestion) 454 return rtLinuxFindDevicePathRecursive(devNum, fMode, "/dev/", 455 pszBuf, cchBuf); 456 457 /* 458 * Construct the filename and read the link. 459 */ 460 char szFilename[RTPATH_MAX]; 461 int rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/", 462 pszSuggestion, va); 463 if (rc == -1) 464 return -1; 465 466 /* 467 * Check whether the caller's suggestion was right. 468 */ 469 /** @todo Should we just be using POSIX stat here? */ 470 RTFSOBJINFO info = {0}; 471 int vrc = RTPathQueryInfo(szFilename, &info, RTFSOBJATTRADD_UNIX); 472 if (RT_FAILURE(vrc)) 473 { 474 errno = (vrc == VERR_PATH_NOT_FOUND) ? ENOENT 475 : (vrc == VERR_FILE_NOT_FOUND) ? ENOENT 476 : EIO; 477 return -1; 478 } 479 if ( (info.Attr.u.Unix.Device == devNum) 480 && ( ( (fMode == RTFS_TYPE_DEV_CHAR) 481 && RTFS_IS_DEV_CHAR(info.Attr.fMode)) 482 || ( (fMode == RTFS_TYPE_DEV_BLOCK) 483 && RTFS_IS_DEV_BLOCK(info.Attr.fMode)))) 484 { 485 size_t cchPath = strlen(szFilename) + 1; 486 if (cchPath > cchBuf) 487 { 488 errno = EOVERFLOW; 489 return -1; 490 } 491 strcpy(pszBuf, szFilename); 492 return cchPath; 493 } 494 495 /* If the suggestion was wrong, try the brute force method */ 496 return rtLinuxFindDevicePathRecursive(devNum, fMode, "/dev/", 497 pszBuf, cchBuf); 498 } 499 500 501 RTDECL(ssize_t) RTLinuxFindDevicePath(dev_t devNum, RTFMODE fMode, 502 char *pszBuf, size_t cchBuf, 503 const char *pszSuggestion, ...) 504 { 505 va_list va; 506 va_start(va, pszSuggestion); 507 int rc = RTLinuxFindDevicePathV(devNum, fMode, pszBuf, cchBuf, 508 pszSuggestion, va); 509 va_end(va); 510 return rc; 511 }
Note:
See TracChangeset
for help on using the changeset viewer.