VirtualBox

Changeset 23309 in vbox for trunk


Ignore:
Timestamp:
Sep 24, 2009 7:44:27 PM (15 years ago)
Author:
vboxsync
Message:

iprt/linux: add APIs for locating device nodes to sysfs APIs

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/linux/sysfs.h

    r20374 r23309  
    3636#include <iprt/stdarg.h>
    3737
     38#include <sys/types.h>
    3839
    3940RT_C_DECLS_BEGIN
     
    119120
    120121/**
     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 */
     128RTDECL(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 */
     137RTDECL(dev_t) RTLinuxSysFsReadDevNumFile(const char *pszFormat, ...);
     138
     139/**
    121140 * Reads a string from a sysfs file.  If the file contains a newline, we only
    122141 * return the text up until there.
     
    178197RTDECL(ssize_t) RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, const char *pszFormat, ...);
    179198
     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 */
     219RTDECL(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 */
     241RTDECL(ssize_t) RTLinuxFindDevicePath(dev_t devNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, const char *pszSuggestion, ...);
     242
    180243/** @} */
    181244
  • trunk/src/VBox/Runtime/r3/linux/sysfs.cpp

    r15644 r23309  
    3636#include <iprt/linux/sysfs.h>
    3737#include <iprt/assert.h>
     38#include <iprt/dir.h>
     39#include <iprt/err.h>
     40#include <iprt/fs.h>
    3841#include <iprt/param.h>
    3942#include <iprt/path.h>
     
    4649#include <sys/fcntl.h>
    4750#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 */
     68static 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 */
     103static 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}
    48113
    49114
     
    63128static ssize_t rtLinuxSysFsConstructPath(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va)
    64129{
    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);
    77131}
    78132
     
    185239
    186240
     241RTDECL(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
     280RTDECL(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
    187290RTDECL(ssize_t) RTLinuxSysFsReadStrFileV(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va)
    188291{
     
    269372}
    270373
     374
     375static 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
     444RTDECL(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
     501RTDECL(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.

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