Example #1
0
/**
 * Validates the extension pack version string.
 *
 * @returns true if valid, false if not.
 * @param   pszVersion          The version string to validate.
 */
bool VBoxExtPackIsValidVersionString(const char *pszVersion)
{
    if (!pszVersion || *pszVersion == '\0')
        return false;

    /* 1.x.y.z... */
    for (;;)
    {
        if (!RT_C_IS_DIGIT(*pszVersion))
            return false;
        do
            pszVersion++;
        while (RT_C_IS_DIGIT(*pszVersion));
        if (*pszVersion != '.')
            break;
        pszVersion++;
    }

    /* upper case string + numbers indicating the build type */
    if (*pszVersion == '-' || *pszVersion == '_')
    {
        /** @todo Should probably restrict this to known build types (alpha,
         *        beta, rc, ++). */
        do
            pszVersion++;
        while (   RT_C_IS_DIGIT(*pszVersion)
               || RT_C_IS_UPPER(*pszVersion)
               || *pszVersion == '-'
               || *pszVersion == '_');
    }

    return *pszVersion == '\0';
}
Example #2
0
/**
 * Converts the fraction part of a generalized time into nanoseconds.
 *
 * @returns IPRT status code.
 * @param   pCursor         The cursor to use when reporting an error.
 * @param   pchFraction     Pointer to the start of the fraction (dot).
 * @param   cchFraction     The length of the fraction.
 * @param   pThis           The time object we're working on,
 *                          Time.u32Nanoseconds will be update.
 * @param   pszErrorTag     The error tag.
 */
static int rtAsn1Time_ConvertGeneralizedTimeFraction(PRTASN1CURSOR pCursor, const char *pchFraction, uint32_t cchFraction,
                                                      PRTASN1TIME pThis, const char *pszErrorTag)
{
    pThis->Time.u32Nanosecond = 0;

    /*
     * Check the dot.
     */
    if (*pchFraction != '.')
        return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_INVALID_GENERALIZED_TIME_ENCODING,
                                   "%s: Expected GeneralizedTime fraction dot, found: '%c' ('%.*s')",
                                   pszErrorTag, *pchFraction, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
    pchFraction++;
    cchFraction--;
    if (!cchFraction)
        return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_INVALID_GENERALIZED_TIME_ENCODING,
                                   "%s: No digit following GeneralizedTime fraction dot: '%.*s'",
                                   pszErrorTag, pThis->Asn1Core.cb, pThis->Asn1Core);

    /*
     * Do the conversion.
     */
    char chLastDigit;
    uint32_t uMult = 100000000;
    do
    {
        char chDigit = chLastDigit = *pchFraction;
        if (!RT_C_IS_DIGIT(chDigit))
            return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_INVALID_GENERALIZED_TIME_ENCODING,
                                       "%s: Bad GeneralizedTime fraction digit: '%.*s'",
                                       pszErrorTag, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
        pThis->Time.u32Nanosecond += uMult * (uint32_t)(chDigit - '0');

        /* Advance */
        cchFraction--;
        pchFraction++;
        uMult /= 10;
    } while (cchFraction > 0 && uMult > 0);

    /*
     * Lazy bird: For now, we don't permit higher resolution than we can
     * internally represent.  Deal with this if it ever becomes an issue.
     */
    if (cchFraction > 0)
        return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_INVALID_GENERALIZED_TIME_ENCODING,
                                   "%s: Bad GeneralizedTime fraction too long: '%.*s'",
                                   pszErrorTag, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
    if (chLastDigit == '0')
        return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_INVALID_GENERALIZED_TIME_ENCODING,
                                   "%s: Trailing zeros not allowed for GeneralizedTime: '%.*s'",
                                   pszErrorTag, pThis->Asn1Core.cb, pThis->Asn1Core.uData.pch);
    return VINF_SUCCESS;
}
Example #3
0
static boolean_t vboxSolarisAddLinkHostIface(const char *pszIface, void *pvHostNetworkInterfaceList)
{
    /*
     * Skip IPSEC interfaces. It's at IP level.
     */
    if (!strncmp(pszIface, "ip.tun", 6))
        return _B_FALSE;

    /*
     * Skip our own dynamic VNICs but don't skip VNIC templates.
     * These names originate from VBoxNetFltBow-solaris.c, hardcoded here for now.
     */
    if (    strncmp(pszIface, "vboxvnic_template", 17)
        && !strncmp(pszIface, "vboxvnic", 8))
        return _B_FALSE;

    /*
     * Clip off the zone instance number from the interface name (if any).
     */
    char szIfaceName[128];
    strcpy(szIfaceName, pszIface);
    char *pszColon = (char *)memchr(szIfaceName, ':', sizeof(szIfaceName));
    if (pszColon)
        *pszColon = '\0';

    /*
     * Get the instance number from the interface name, then clip it off.
     */
    int cbInstance = 0;
    int cbIface = strlen(szIfaceName);
    const char *pszEnd = pszIface + cbIface - 1;
    for (int i = 0; i < cbIface - 1; i++)
    {
        if (!RT_C_IS_DIGIT(*pszEnd))
            break;
        cbInstance++;
        pszEnd--;
    }

    int Instance = atoi(pszEnd + 1);
    strncpy(szIfaceName, pszIface, cbIface - cbInstance);
    szIfaceName[cbIface - cbInstance] = '\0';

    /*
     * Add the interface.
     */
    vboxSolarisAddHostIface(szIfaceName, Instance, pvHostNetworkInterfaceList);

    /*
     * Continue walking...
     */
    return _B_FALSE;
}
Example #4
0
char *CollectorLinux::trimTrailingDigits(char *pszName)
{
    unsigned cbName = strlen(pszName);
    if (cbName == 0)
        return pszName;

    char *pszEnd = pszName + cbName - 1;
    while (pszEnd > pszName && (RT_C_IS_DIGIT(*pszEnd) || *pszEnd == '\n'))
        pszEnd--;
    pszEnd[1] = '\0';

    return pszName;
}
Example #5
0
/* static */
DECLCALLBACK(int)  Guest::i_staticEnumStatsCallback(const char *pszName, STAMTYPE enmType, void *pvSample,
                                                    STAMUNIT enmUnit, STAMVISIBILITY enmVisiblity,
                                                    const char *pszDesc, void *pvUser)
{
    AssertLogRelMsgReturn(enmType == STAMTYPE_COUNTER, ("Unexpected sample type %d ('%s')\n", enmType, pszName), VINF_SUCCESS);
    AssertLogRelMsgReturn(enmUnit == STAMUNIT_BYTES, ("Unexpected sample unit %d ('%s')\n", enmUnit, pszName), VINF_SUCCESS);

    /* Get the base name w/ slash. */
    const char *pszLastSlash = strrchr(pszName, '/');
    AssertLogRelMsgReturn(pszLastSlash, ("Unexpected sample '%s'\n", pszName), VINF_SUCCESS);

    /* Receive or transmit? */
    bool fRx;
    if (!strcmp(pszLastSlash, "/BytesReceived"))
        fRx = true;
    else if (!strcmp(pszLastSlash, "/BytesTransmitted"))
        fRx = false;
    else
        AssertLogRelMsgFailedReturn(("Unexpected sample '%s'\n", pszName), VINF_SUCCESS);

#if 0 /* not used for anything, so don't bother parsing it. */
    /* Find start of instance number. ASSUMES '/Public/Net/Name<Instance digits>/Bytes...' */
    do
        --pszLastSlash;
    while (pszLastSlash > pszName && RT_C_IS_DIGIT(*pszLastSlash));
    pszLastSlash++;

    uint8_t uInstance;
    int rc = RTStrToUInt8Ex(pszLastSlash, NULL, 10, &uInstance);
    AssertLogRelMsgReturn(RT_SUCCESS(rc) && rc != VWRN_NUMBER_TOO_BIG && rc != VWRN_NEGATIVE_UNSIGNED,
                          ("%Rrc '%s'\n", rc, pszName), VINF_SUCCESS)
#endif

    /* Add the bytes to our counters. */
    PSTAMCOUNTER pCnt   = (PSTAMCOUNTER)pvSample;
    Guest       *pGuest = (Guest *)pvUser;
    uint64_t     cb     = pCnt->c;
#if 0
    LogFlowFunc(("%s i=%u d=%s %llu bytes\n", pszName, uInstance, fRx ? "RX" : "TX", cb));
#else
    LogFlowFunc(("%s d=%s %llu bytes\n", pszName, fRx ? "RX" : "TX", cb));
#endif
    if (fRx)
        pGuest->mNetStatRx += cb;
    else
        pGuest->mNetStatTx += cb;

    return VINF_SUCCESS;
}
Example #6
0
/**
 * Use the partition name to get the name of the disk. Any path component is stripped.
 * if fTrimDigits is true, trailing digits are stripped as well, for example '/dev/sda5'
 * is converted to 'sda'.
 *
 * @param   pszDiskName     Where to store the name of the disk.
 * @param   cbDiskName      The size of the buffer pszDiskName points to.
 * @param   pszDevName      The device name used to get the disk name.
 * @param   fTrimDigits     Trim trailing digits (e.g. /dev/sda5)
 */
void CollectorLinux::getDiskName(char *pszDiskName, size_t cbDiskName, const char *pszDevName, bool fTrimDigits)
{
    unsigned cbName = 0;
    unsigned cbDevName = strlen(pszDevName);
    const char *pszEnd = pszDevName + cbDevName - 1;
    if (fTrimDigits)
        while (pszEnd > pszDevName && RT_C_IS_DIGIT(*pszEnd))
            pszEnd--;
    while (pszEnd > pszDevName && *pszEnd != '/')
    {
        cbName++;
        pszEnd--;
    }
    RTStrCopy(pszDiskName, RT_MIN(cbName + 1, cbDiskName), pszEnd + 1);
}
Example #7
0
/**
 * Validates the extension pack edition string.
 *
 * @returns true if valid, false if not.
 * @param   pszEdition          The edition string to validate.
 */
bool VBoxExtPackIsValidEditionString(const char *pszEdition)
{
    if (*pszEdition)
    {
        if (!RT_C_IS_UPPER(*pszEdition))
            return false;

        do
            pszEdition++;
        while (   RT_C_IS_UPPER(*pszEdition)
               || RT_C_IS_DIGIT(*pszEdition)
               || *pszEdition == '-'
               || *pszEdition == '_');
    }
    return *pszEdition == '\0';
}
/**
 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
 */
static DECLCALLBACK(int) rtVfsChainGzip_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
                                                 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
{
    RT_NOREF(pProviderReg);

    /*
     * Basics.
     */
    if (pElement->enmType != RTVFSOBJTYPE_IO_STREAM)
        return VERR_VFS_CHAIN_ONLY_IOS;
    if (pElement->enmTypeIn == RTVFSOBJTYPE_INVALID)
        return VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT;
    if (   pElement->enmTypeIn != RTVFSOBJTYPE_FILE
        && pElement->enmTypeIn != RTVFSOBJTYPE_IO_STREAM)
        return VERR_VFS_CHAIN_TAKES_FILE_OR_IOS;
    if (pSpec->fOpenFile & RTFILE_O_READ)
        return VERR_VFS_CHAIN_WRITE_ONLY_IOS;
    if (pElement->cArgs > 1)
        return VERR_VFS_CHAIN_AT_MOST_ONE_ARG;

    /*
     * Optional argument 1..9 indicating the compression level.
     * We store it in pSpec->uProvider.
     */
    if (pElement->cArgs > 0)
    {
        const char *psz = pElement->paArgs[0].psz;
        if (!*psz || !strcmp(psz, "default"))
            pElement->uProvider = 6;
        else if (!strcmp(psz, "fast"))
            pElement->uProvider = 3;
        else if (   RT_C_IS_DIGIT(*psz)
                 && *psz != '0'
                 && *RTStrStripL(psz + 1) == '\0')
            pElement->uProvider = *psz - '0';
        else
        {
            *poffError = pElement->paArgs[0].offSpec;
            return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected compression level: 1-9, default, or fast");
        }
    }
    else
        pElement->uProvider = 6;

    return VINF_SUCCESS;
}
Example #9
0
/* static */
int Guest::staticEnumStatsCallback(const char *pszName, STAMTYPE enmType, void *pvSample, STAMUNIT enmUnit,
                                          STAMVISIBILITY enmVisiblity, const char *pszDesc, void *pvUser)
{
    PSTAMCOUNTER pCnt = (PSTAMCOUNTER)pvSample;
    char *pszEnd = strrchr((char*)pszName, '/');
    if (pszEnd)
    {
        bool    fRx;
        uint8_t uInstance = 0;

        switch (pszEnd[1])
        {
            case 'R':
                fRx = true;
                break;
            case 'T':
                fRx = false;
                break;
            default:
                LogRel(("Failed to parse the name of network stat counter (unknown counter): %s\n", pszName));
                return VINF_SUCCESS;
        }
        do
            --pszEnd;
        while (pszEnd > pszName && RT_C_IS_DIGIT(*pszEnd));
        if (RT_SUCCESS(RTStrToUInt8Ex(pszEnd + 1, NULL, 10, &uInstance)))
        {
            Guest *pGuest = (Guest *)pvUser;
            LogFlowFunc(("%s i=%u d=%s %llu %s\n", pszName, uInstance, fRx ? "RX" : "TX",
                         pCnt->c, STAMR3GetUnit(enmUnit)));
            if (fRx)
                pGuest->mNetStatRx += pCnt->c;
            else
                pGuest->mNetStatTx += pCnt->c;
        }
        else
            LogRel(("Failed to extract the device instance from the name of network stat counter: %s\n", pszEnd));
    }
    else
        LogRel(("Failed to parse the name of network stat counter (no slash): %s\n", pszName));

    return VINF_SUCCESS;
}
Example #10
0
static void test3(void)
{
    RTTestISub("> 127");
    for (int ch = 128; ch < 2000000; ch++)
    {
        RTTESTI_CHECK(!RT_C_IS_CNTRL(ch));
        RTTESTI_CHECK(!RT_C_IS_SPACE(ch));
        RTTESTI_CHECK(!RT_C_IS_BLANK(ch));
        RTTESTI_CHECK(!RT_C_IS_PRINT(ch));
        RTTESTI_CHECK(!RT_C_IS_PUNCT(ch));
        RTTESTI_CHECK(!RT_C_IS_GRAPH(ch));
        RTTESTI_CHECK(!RT_C_IS_DIGIT(ch));
        RTTESTI_CHECK(!RT_C_IS_XDIGIT(ch));
        RTTESTI_CHECK(!RT_C_IS_ODIGIT(ch));
        RTTESTI_CHECK(!RT_C_IS_ALPHA(ch));
        RTTESTI_CHECK(!RT_C_IS_UPPER(ch));
        RTTESTI_CHECK(!RT_C_IS_LOWER(ch));
    }
}
Example #11
0
static void test2(void)
{
    RTTestISub("< 0");
    for (int ch = -1; ch > -2000000; ch--)
    {
        RTTESTI_CHECK(!RT_C_IS_CNTRL(ch));
        RTTESTI_CHECK(!RT_C_IS_SPACE(ch));
        RTTESTI_CHECK(!RT_C_IS_BLANK(ch));
        RTTESTI_CHECK(!RT_C_IS_PRINT(ch));
        RTTESTI_CHECK(!RT_C_IS_PUNCT(ch));
        RTTESTI_CHECK(!RT_C_IS_GRAPH(ch));
        RTTESTI_CHECK(!RT_C_IS_DIGIT(ch));
        RTTESTI_CHECK(!RT_C_IS_XDIGIT(ch));
        RTTESTI_CHECK(!RT_C_IS_ODIGIT(ch));
        RTTESTI_CHECK(!RT_C_IS_ALPHA(ch));
        RTTESTI_CHECK(!RT_C_IS_UPPER(ch));
        RTTESTI_CHECK(!RT_C_IS_LOWER(ch));
    }
}
Example #12
0
uint32_t CollectorSolaris::getInstance(const char *pszIfaceName, char *pszDevName)
{
    /*
     * Get the instance number from the interface name, then clip it off.
     */
    int cbInstance = 0;
    int cbIface = strlen(pszIfaceName);
    const char *pszEnd = pszIfaceName + cbIface - 1;
    for (int i = 0; i < cbIface - 1; i++)
    {
        if (!RT_C_IS_DIGIT(*pszEnd))
            break;
        cbInstance++;
        pszEnd--;
    }

    uint32_t uInstance = RTStrToUInt32(pszEnd + 1);
    strncpy(pszDevName, pszIfaceName, cbIface - cbInstance);
    pszDevName[cbIface - cbInstance] = '\0';
    return uInstance;
}
Example #13
0
/**
 * Searches for a long option.
 *
 * @returns Pointer to a matching option.
 * @param   pszOption       The alleged long option.
 * @param   paOptions       Option array.
 * @param   cOptions        Number of items in the array.
 * @param   fFlags          Init flags.
 */
static PCRTGETOPTDEF rtGetOptSearchLong(const char *pszOption, PCRTGETOPTDEF paOptions, size_t cOptions, uint32_t fFlags)
{
    PCRTGETOPTDEF pOpt = paOptions;
    while (cOptions-- > 0)
    {
        if (pOpt->pszLong)
        {
            if ((pOpt->fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING)
            {
                /*
                 * A value is required with the argument. We're trying to be
                 * understanding here and will permit any of the following:
                 *      --long12:value,  --long12=value, --long12 value,
                 *      --long:value,    --long=value,   --long value,
                 *
                 * If the option is index, then all trailing chars must be
                 * digits.  For error reporting reasons we also match where
                 * there is no index.
                 */
                size_t cchLong = strlen(pOpt->pszLong);
                if (   !strncmp(pszOption, pOpt->pszLong, cchLong)
                    || (   pOpt->fFlags & RTGETOPT_FLAG_ICASE
                        && !RTStrNICmp(pszOption, pOpt->pszLong, cchLong)))
                {
                    if (pOpt->fFlags & RTGETOPT_FLAG_INDEX)
                        while (RT_C_IS_DIGIT(pszOption[cchLong]))
                            cchLong++;
                    if (   pszOption[cchLong] == '\0'
                        || pszOption[cchLong] == ':'
                        || pszOption[cchLong] == '=')
                        return pOpt;
                }
            }
            else if (pOpt->fFlags & RTGETOPT_FLAG_INDEX)
            {
                /*
                 * The option takes an index but no value.
                 * As above, we also match where there is no index.
                 */
                size_t cchLong = strlen(pOpt->pszLong);
                if (   !strncmp(pszOption, pOpt->pszLong, cchLong)
                    || (   pOpt->fFlags & RTGETOPT_FLAG_ICASE
                        && !RTStrNICmp(pszOption, pOpt->pszLong, cchLong)))
                {
                    while (RT_C_IS_DIGIT(pszOption[cchLong]))
                        cchLong++;
                    if (pszOption[cchLong] == '\0')
                        return pOpt;
                }
            }
            else if (   !strcmp(pszOption, pOpt->pszLong)
                     || (   pOpt->fFlags & RTGETOPT_FLAG_ICASE
                         && !RTStrICmp(pszOption, pOpt->pszLong)))
                return pOpt;
        }
        pOpt++;
    }

    if (!(fFlags & RTGETOPTINIT_FLAGS_NO_STD_OPTS))
        for (uint32_t i = 0; i < RT_ELEMENTS(g_aStdOptions); i++)
            if (   !strcmp(pszOption, g_aStdOptions[i].pszLong)
                || (   g_aStdOptions[i].fFlags & RTGETOPT_FLAG_ICASE
                    && !RTStrICmp(pszOption, g_aStdOptions[i].pszLong)))
                return &g_aStdOptions[i];

    return NULL;
}
Example #14
0
int CollectorLinux::getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms)
{
#if 0
    int rc = VINF_SUCCESS;
    char szIfName[/*IFNAMSIZ*/ 16 + 36];
    long long unsigned int u64Busy, tmp;

    RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/block/%s/stat", name);
    FILE *f = fopen(szIfName, "r");
    if (f)
    {
        if (fscanf(f, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
                   &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &u64Busy, &tmp) == 11)
        {
            *disk_ms   = u64Busy;
            *total_ms  = (uint64_t)(mSingleUser + mSingleKernel + mSingleIdle) * 1000 / mHZ;
        }
        else
            rc = VERR_FILE_IO_ERROR;
        fclose(f);
    }
    else
        rc = VERR_ACCESS_DENIED;
#else
    int rc = VERR_MISSING;
    FILE *f = fopen("/proc/diskstats", "r");
    if (f)
    {
        char szBuf[128];
        while (fgets(szBuf, sizeof(szBuf), f))
        {
            char *pszBufName = szBuf;
            while (*pszBufName == ' ')         ++pszBufName; /* Skip spaces */
            while (RT_C_IS_DIGIT(*pszBufName)) ++pszBufName; /* Skip major */
            while (*pszBufName == ' ')         ++pszBufName; /* Skip spaces */
            while (RT_C_IS_DIGIT(*pszBufName)) ++pszBufName; /* Skip minor */
            while (*pszBufName == ' ')         ++pszBufName; /* Skip spaces */

            char *pszBufData = strchr(pszBufName, ' ');
            if (!pszBufData)
            {
                LogRel(("CollectorLinux::getRawHostDiskLoad() failed to parse disk stats: %s\n", szBuf));
                continue;
            }
            *pszBufData++ = '\0';
            if (!strcmp(name, pszBufName))
            {
                long long unsigned int u64Busy, tmp;

                if (sscanf(pszBufData, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
                           &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &u64Busy, &tmp) == 11)
                {
                    *disk_ms   = u64Busy;
                    *total_ms  = (uint64_t)(mSingleUser + mSingleKernel + mSingleIdle) * 1000 / mHZ;
                    rc = VINF_SUCCESS;
                }
                else
                    rc = VERR_FILE_IO_ERROR;
                break;
            }
        }
        fclose(f);
    }
#endif

    return rc;
}
Example #15
0
/**
 * Converts the UTCTime string into an the RTTIME member of RTASN1TIME.
 *
 * @returns IPRT status code.
 * @param   pCursor             The cursor to use when reporting an error.
 * @param   pThis               The time to parse.
 * @param   pszErrorTag         The error tag.
 */
static int rtAsn1Time_ConvertUTCTime(PRTASN1CURSOR pCursor, PRTASN1TIME pThis, const char *pszErrorTag)
{
    /*
     * While the current spec says the seconds field is not optional, this
     * restriction was added later on.  So, when parsing UTCTime we must deal
     * with it being absent.
     */
    int rc;
    bool fHaveSeconds = pThis->Asn1Core.cb == sizeof("YYMMDDHHMMSSZ") - 1;
    if (fHaveSeconds || pThis->Asn1Core.cb == sizeof("YYMMDDHHMMZ") - 1)
    {
        const char *pachTime = pThis->Asn1Core.uData.pch;

        /* Basic encoding validation. */
        if (   RT_C_IS_DIGIT(pachTime[0]) /* Y */
            && RT_C_IS_DIGIT(pachTime[1]) /* Y */
            && RT_C_IS_DIGIT(pachTime[2]) /* M */
            && RT_C_IS_DIGIT(pachTime[3]) /* M */
            && RT_C_IS_DIGIT(pachTime[4]) /* D */
            && RT_C_IS_DIGIT(pachTime[5]) /* D */
            && RT_C_IS_DIGIT(pachTime[6]) /* H */
            && RT_C_IS_DIGIT(pachTime[7]) /* H */
            && RT_C_IS_DIGIT(pachTime[8]) /* M */
            && RT_C_IS_DIGIT(pachTime[9]) /* M */
            && (   !fHaveSeconds
                || (   RT_C_IS_DIGIT(pachTime[10]) /* S */
                    && RT_C_IS_DIGIT(pachTime[11]) /* S */ ) )
            && pachTime[fHaveSeconds ? 12 : 10] == 'Z'
           )
        {
            /* Basic conversion. */
            pThis->Time.i32Year         = (pachTime[0] - '0') * 10  +  (pachTime[1] - '0');
            pThis->Time.i32Year        += pThis->Time.i32Year < 50 ? 2000 : 1900;
            pThis->Time.u8Month         = (pachTime[2] - '0') * 10  +  (pachTime[3] - '0');
            pThis->Time.u8WeekDay       = 0;
            pThis->Time.u16YearDay      = 0;
            pThis->Time.u8MonthDay      = (pachTime[4] - '0') * 10  +  (pachTime[5] - '0');
            pThis->Time.u8Hour          = (pachTime[6] - '0') * 10  +  (pachTime[7] - '0');
            pThis->Time.u8Minute        = (pachTime[8] - '0') * 10  +  (pachTime[9] - '0');
            if (fHaveSeconds)
                pThis->Time.u8Second    = (pachTime[10] - '0') * 10 +  (pachTime[11] - '0');
            else
                pThis->Time.u8Second    = 0;
            pThis->Time.u32Nanosecond   = 0;
            pThis->Time.fFlags          = RTTIME_FLAGS_TYPE_UTC;
            pThis->Time.offUTC          = 0;

            /* Check the convered data and normalize the time structure. */
            rc = rtAsn1Time_NormalizeTime(pCursor, pThis, "UTCTime", pszErrorTag);
            if (RT_SUCCESS(rc))
                return rc;
        }
        else
            rc = RTAsn1CursorSetInfo(pCursor, VERR_ASN1_INVALID_UTC_TIME_ENCODING, "%s: Bad UTCTime encoding: '%.*s'",
                                     pszErrorTag, pThis->Asn1Core.cb, pachTime);
    }
    else
        rc = RTAsn1CursorSetInfo(pCursor, VERR_ASN1_INVALID_UTC_TIME_ENCODING, "%s: Bad UTCTime length: %#x",
                                 pszErrorTag, pThis->Asn1Core.cb);
    RT_ZERO(*pThis);
    return rc;
}
Example #16
0
/**
 * Converts the GeneralizedTime string into an the RTTIME member of RTASN1TIME.
 *
 * @returns IPRT status code.
 * @param   pCursor             The cursor to use when reporting an error.
 * @param   pThis               The time to parse.
 * @param   pszErrorTag         The error tag.
 */
static int rtAsn1Time_ConvertGeneralizedTime(PRTASN1CURSOR pCursor, PRTASN1TIME pThis, const char *pszErrorTag)
{
    int rc;
    if (pThis->Asn1Core.cb >= sizeof("YYYYMMDDHHMMSSZ") - 1)
    {
        const char *pachTime = pThis->Asn1Core.uData.pch;

        /* Basic encoding validation. */
        if (   RT_C_IS_DIGIT(pachTime[0]) /* Y */
            && RT_C_IS_DIGIT(pachTime[1]) /* Y */
            && RT_C_IS_DIGIT(pachTime[2]) /* Y */
            && RT_C_IS_DIGIT(pachTime[3]) /* Y */
            && RT_C_IS_DIGIT(pachTime[4]) /* M */
            && RT_C_IS_DIGIT(pachTime[5]) /* M */
            && RT_C_IS_DIGIT(pachTime[6]) /* D */
            && RT_C_IS_DIGIT(pachTime[7]) /* D */
            && RT_C_IS_DIGIT(pachTime[8]) /* H */
            && RT_C_IS_DIGIT(pachTime[9]) /* H */
            && RT_C_IS_DIGIT(pachTime[10]) /* M */
            && RT_C_IS_DIGIT(pachTime[11]) /* M */
            && RT_C_IS_DIGIT(pachTime[12]) /* S */ /** @todo was this once optional? */
            && RT_C_IS_DIGIT(pachTime[13]) /* S */
            && pachTime[pThis->Asn1Core.cb - 1] == 'Z'
           )
        {
            /* Basic conversion. */
            pThis->Time.i32Year         = 1000 * (pachTime[0] - '0')
                                        +  100 * (pachTime[1] - '0')
                                        +   10 * (pachTime[2] - '0')
                                        +        (pachTime[3] - '0');
            pThis->Time.u8Month         = (pachTime[4]  - '0') * 10  +  (pachTime[5]  - '0');
            pThis->Time.u8WeekDay       = 0;
            pThis->Time.u16YearDay      = 0;
            pThis->Time.u8MonthDay      = (pachTime[6]  - '0') * 10  +  (pachTime[7]  - '0');
            pThis->Time.u8Hour          = (pachTime[8]  - '0') * 10  +  (pachTime[9]  - '0');
            pThis->Time.u8Minute        = (pachTime[10] - '0') * 10  +  (pachTime[11] - '0');
            pThis->Time.u8Second        = (pachTime[12] - '0') * 10  +  (pachTime[13] - '0');
            pThis->Time.u32Nanosecond   = 0;
            pThis->Time.fFlags          = RTTIME_FLAGS_TYPE_UTC;
            pThis->Time.offUTC          = 0;

            /* Optional fraction part. */
            rc = VINF_SUCCESS;
            uint32_t cchLeft = pThis->Asn1Core.cb - 14 - 1;
            if (cchLeft > 0)
                rc = rtAsn1Time_ConvertGeneralizedTimeFraction(pCursor, pachTime + 14, cchLeft, pThis, pszErrorTag);

            /* Check the convered data and normalize the time structure. */
            if (RT_SUCCESS(rc))
            {
                rc = rtAsn1Time_NormalizeTime(pCursor, pThis, "GeneralizedTime", pszErrorTag);
                if (RT_SUCCESS(rc))
                    return VINF_SUCCESS;
            }
        }
        else
            rc = RTAsn1CursorSetInfo(pCursor, VERR_ASN1_INVALID_GENERALIZED_TIME_ENCODING,
                                     "%s: Bad GeneralizedTime encoding: '%.*s'",
                                     pszErrorTag, pThis->Asn1Core.cb, pachTime);
    }
    else
        rc = RTAsn1CursorSetInfo(pCursor, VERR_ASN1_INVALID_GENERALIZED_TIME_ENCODING,
                                 "%s: Bad GeneralizedTime length: %#x",
                                 pszErrorTag, pThis->Asn1Core.cb);
    RT_ZERO(*pThis);
    return rc;
}
Example #17
0
static char *rtUriPercentDecodeN(const char *pszString, size_t cchString)
{
    AssertPtrReturn(pszString, NULL);
    AssertReturn(memchr(pszString, '\0', cchString) == NULL, NULL);

    /*
     * The new string can only get smaller, so use the input length as a
     * staring buffer size.
     */
    char *pszDecoded = RTStrAlloc(cchString + 1);
    if (pszDecoded)
    {
        /*
         * Knowing that the pszString itself is valid UTF-8, we only have to
         * validate the escape sequences.
         */
        size_t      cchLeft = cchString;
        char const *pchSrc  = pszString;
        char       *pchDst  = pszDecoded;
        while (cchLeft > 0)
        {
            const char *pchPct = (const char *)memchr(pchSrc, '%', cchLeft);
            if (pchPct)
            {
                size_t cchBefore = pchPct - pchSrc;
                if (cchBefore)
                {
                    memcpy(pchDst, pchSrc, cchBefore);
                    pchDst  += cchBefore;
                    pchSrc  += cchBefore;
                    cchLeft -= cchBefore;
                }

                char chHigh, chLow;
                if (   cchLeft >= 3
                    && RT_C_IS_XDIGIT(chHigh = pchSrc[1])
                    && RT_C_IS_XDIGIT(chLow  = pchSrc[2]))
                {
                    uint8_t b = RT_C_IS_DIGIT(chHigh) ? chHigh - '0' : (chHigh & ~0x20) - 'A' + 10;
                    b <<= 4;
                    b |= RT_C_IS_DIGIT(chLow) ? chLow - '0' : (chLow & ~0x20) - 'A' + 10;
                    *pchDst++ = (char)b;
                    pchSrc  += 3;
                    cchLeft -= 3;
                }
                else
                {
                    AssertFailed();
                    *pchDst++ = *pchSrc++;
                    cchLeft--;
                }
            }
            else
            {
                memcpy(pchDst, pchSrc, cchLeft);
                pchDst += cchLeft;
                pchSrc += cchLeft;
                cchLeft = 0;
                break;
            }
        }

        *pchDst = '\0';

        /*
         * If we've got lof space room in the result string, reallocate it.
         */
        size_t cchDecoded = pchDst - pszDecoded;
        Assert(cchDecoded <= cchString);
        if (cchString - cchDecoded > 64)
            RTStrRealloc(&pszDecoded, cchDecoded + 1);
    }
    return pszDecoded;
}
Example #18
0
/**
 * Decodes a string into a buffer.
 *
 * @returns IPRT status code.
 * @param   pchSrc      The source string.
 * @param   cchSrc      The max number of bytes to decode in the source string.
 * @param   pszDst      The destination buffer.
 * @param   cbDst       The size of the buffer (including terminator).
 */
static int rtUriDecodeIntoBuffer(const char *pchSrc, size_t cchSrc, char *pszDst, size_t cbDst)
{
    AssertPtrReturn(pchSrc, VERR_INVALID_POINTER);
    AssertPtrReturn(pszDst, VERR_INVALID_POINTER);

    /*
     * Knowing that the pszString itself is valid UTF-8, we only have to
     * validate the escape sequences.
     */
    cchSrc = RTStrNLen(pchSrc, cchSrc);
    while (cchSrc > 0)
    {
        const char *pchPct = (const char *)memchr(pchSrc, '%', cchSrc);
        if (pchPct)
        {
            size_t cchBefore = pchPct - pchSrc;
            AssertReturn(cchBefore + 1 < cbDst, VERR_BUFFER_OVERFLOW);
            if (cchBefore)
            {
                memcpy(pszDst, pchSrc, cchBefore);
                pszDst += cchBefore;
                cbDst  -= cchBefore;
                pchSrc += cchBefore;
                cchSrc -= cchBefore;
            }

            char chHigh, chLow;
            if (   cchSrc >= 3
                && RT_C_IS_XDIGIT(chHigh = pchSrc[1])
                && RT_C_IS_XDIGIT(chLow  = pchSrc[2]))
            {
                uint8_t b = RT_C_IS_DIGIT(chHigh) ? chHigh - '0' : (chHigh & ~0x20) - 'A' + 10;
                b <<= 4;
                b |= RT_C_IS_DIGIT(chLow) ? chLow - '0' : (chLow & ~0x20) - 'A' + 10;
                *pszDst++ = (char)b;
                pchSrc += 3;
                cchSrc -= 3;
            }
            else
            {
                AssertFailed();
                *pszDst++ = *pchSrc++;
                cchSrc--;
            }
            cbDst -= 1;
        }
        else
        {
            AssertReturn(cchSrc < cbDst, VERR_BUFFER_OVERFLOW);
            memcpy(pszDst, pchSrc, cchSrc);
            pszDst += cchSrc;
            cbDst  -= cchSrc;
            pchSrc += cchSrc;
            cchSrc  = 0;
            break;
        }
    }

    AssertReturn(cbDst > 0, VERR_BUFFER_OVERFLOW);
    *pszDst = '\0';
    return VINF_SUCCESS;
}
Example #19
0
static int rtUriParse(const char *pszUri, PRTURIPARSED pParsed)
{
    /*
     * Validate the input and clear the output.
     */
    AssertPtrReturn(pParsed, VERR_INVALID_POINTER);
    RT_ZERO(*pParsed);
    pParsed->uAuthorityPort = UINT32_MAX;

    AssertPtrReturn(pszUri, VERR_INVALID_POINTER);

    size_t const cchUri = strlen(pszUri);
    if (RT_LIKELY(cchUri >= 3)) { /* likely */ }
    else return cchUri ? VERR_URI_TOO_SHORT : VERR_URI_EMPTY;

    /*
     * Validating escaped text sequences is much simpler if we know that
     * that the base URI string is valid.  Also, we don't necessarily trust
     * the developer calling us to remember to do this.
     */
    int rc = RTStrValidateEncoding(pszUri);
    AssertRCReturn(rc, rc);

    /*
     * RFC-3986, section 3.1:
     *      scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
     *
     * The scheme ends with a ':', which we also skip here.
     */
    size_t off = 0;
    char ch = pszUri[off++];
    if (RT_LIKELY(RT_C_IS_ALPHA(ch))) { /* likely */ }
    else return VERR_URI_INVALID_SCHEME;
    for (;;)
    {
        ch = pszUri[off];
        if (ch == ':')
            break;
        if (RT_LIKELY(RT_C_IS_ALNUM(ch) || ch == '.' || ch == '-' || ch == '+')) { /* likely */ }
        else return VERR_URI_INVALID_SCHEME;
        off++;
    }
    pParsed->cchScheme = off;

    /* Require the scheme length to be at least two chars so we won't confuse
       it with a path starting with a DOS drive letter specification. */
    if (RT_LIKELY(off >= 2)) { /* likely */ }
    else return VERR_URI_INVALID_SCHEME;

    off++;                              /* (skip colon) */

    /*
     * Find the end of the path, we'll need this several times.
     * Also, while we're potentially scanning the whole thing, check for '%'.
     */
    size_t const offHash         = RTStrOffCharOrTerm(&pszUri[off], '#') + off;
    size_t const offQuestionMark = RTStrOffCharOrTerm(&pszUri[off], '?') + off;

    if (memchr(pszUri, '%', cchUri) != NULL)
        pParsed->fFlags |= RTURIPARSED_F_CONTAINS_ESCAPED_CHARS;

    /*
     * RFC-3986, section 3.2:
     *      The authority component is preceeded by a double slash ("//")...
     */
    if (   pszUri[off] == '/'
        && pszUri[off + 1] == '/')
    {
        off += 2;
        pParsed->offAuthority = pParsed->offAuthorityUsername = pParsed->offAuthorityPassword = pParsed->offAuthorityHost = off;
        pParsed->fFlags |= RTURIPARSED_F_HAVE_AUTHORITY;

        /*
         * RFC-3986, section 3.2:
         *      ...and is terminated by the next slash ("/"), question mark ("?"),
         *       or number sign ("#") character, or by the end of the URI.
         */
        const char *pszAuthority = &pszUri[off];
        size_t      cchAuthority = RTStrOffCharOrTerm(pszAuthority, '/');
        cchAuthority = RT_MIN(cchAuthority, offHash - off);
        cchAuthority = RT_MIN(cchAuthority, offQuestionMark - off);
        pParsed->cchAuthority     = cchAuthority;

        /* The Authority can be empty, like for: file:///usr/bin/grep  */
        if (cchAuthority > 0)
        {
            pParsed->cchAuthorityHost = cchAuthority;

            /*
             * If there is a userinfo part, it is ended by a '@'.
             */
            const char *pszAt = (const char *)memchr(pszAuthority, '@', cchAuthority);
            if (pszAt)
            {
                size_t cchTmp = pszAt - pszAuthority;
                pParsed->offAuthorityHost += cchTmp + 1;
                pParsed->cchAuthorityHost -= cchTmp + 1;

                /* If there is a password part, it's separated from the username with a colon. */
                const char *pszColon = (const char *)memchr(pszAuthority, ':', cchTmp);
                if (pszColon)
                {
                    pParsed->cchAuthorityUsername = pszColon - pszAuthority;
                    pParsed->offAuthorityPassword = &pszColon[1] - pszUri;
                    pParsed->cchAuthorityPassword = pszAt - &pszColon[1];
                }
                else
                {
                    pParsed->cchAuthorityUsername = cchTmp;
                    pParsed->offAuthorityPassword = off + cchTmp;
                }
            }

            /*
             * If there is a port part, its after the last colon in the host part.
             */
            const char *pszColon = (const char *)memrchr(&pszUri[pParsed->offAuthorityHost], ':', pParsed->cchAuthorityHost);
            if (pszColon)
            {
                size_t cchTmp = &pszUri[pParsed->offAuthorityHost + pParsed->cchAuthorityHost] - &pszColon[1];
                pParsed->cchAuthorityHost -= cchTmp + 1;

                pParsed->uAuthorityPort = 0;
                while (cchTmp-- > 0)
                {
                    ch = *++pszColon;
                    if (   RT_C_IS_DIGIT(ch)
                        && pParsed->uAuthorityPort < UINT32_MAX / UINT32_C(10))
                    {
                        pParsed->uAuthorityPort *= 10;
                        pParsed->uAuthorityPort += ch - '0';
                    }
                    else
                        return VERR_URI_INVALID_PORT_NUMBER;
                }
            }
        }

        /* Skip past the authority. */
        off += cchAuthority;
    }
    else
        pParsed->offAuthority = pParsed->offAuthorityUsername = pParsed->offAuthorityPassword = pParsed->offAuthorityHost = off;

    /*
     * RFC-3986, section 3.3: Path
     *      The path is terminated by the first question mark ("?")
     *      or number sign ("#") character, or by the end of the URI.
     */
    pParsed->offPath = off;
    pParsed->cchPath = RT_MIN(offHash, offQuestionMark) - off;
    off += pParsed->cchPath;

    /*
     * RFC-3986, section 3.4: Query
     *      The query component is indicated by the first question mark ("?")
     *      character and terminated by a number sign ("#") character or by the
     *      end of the URI.
     */
    if (   off == offQuestionMark
        && off < cchUri)
    {
        Assert(pszUri[offQuestionMark] == '?');
        pParsed->offQuery = ++off;
        pParsed->cchQuery = offHash - off;
        off = offHash;
    }
    else
    {
        Assert(!pszUri[offQuestionMark]);
        pParsed->offQuery = off;
    }

    /*
     * RFC-3986, section 3.5: Fragment
     *      A fragment identifier component is indicated by the presence of a
     *      number sign ("#") character and terminated by the end of the URI.
     */
    if (   off == offHash
        && off < cchUri)
    {
        pParsed->offFragment = ++off;
        pParsed->cchFragment = cchUri - off;
    }
    else
    {
        Assert(!pszUri[offHash]);
        pParsed->offFragment = off;
    }

    /*
     * If there are any escape sequences, validate them.
     *
     * This is reasonably simple as we already know that the string is valid UTF-8
     * before they get decoded.  Thus we only have to validate the escaped sequences.
     */
    if (pParsed->fFlags & RTURIPARSED_F_CONTAINS_ESCAPED_CHARS)
    {
        const char *pchSrc  = (const char *)memchr(pszUri, '%', cchUri);
        AssertReturn(pchSrc, VERR_INTERNAL_ERROR);
        do
        {
            char        szUtf8Seq[8];
            unsigned    cchUtf8Seq = 0;
            unsigned    cchNeeded  = 0;
            size_t      cchLeft    = &pszUri[cchUri] - pchSrc;
            do
            {
                if (cchLeft >= 3)
                {
                    char chHigh = pchSrc[1];
                    char chLow  = pchSrc[2];
                    if (   RT_C_IS_XDIGIT(chHigh)
                        && RT_C_IS_XDIGIT(chLow))
                    {
                        uint8_t b = RT_C_IS_DIGIT(chHigh) ? chHigh - '0' : (chHigh & ~0x20) - 'A' + 10;
                        b <<= 4;
                        b |= RT_C_IS_DIGIT(chLow) ? chLow - '0' : (chLow & ~0x20) - 'A' + 10;

                        if (!(b & 0x80))
                        {
                            /* We don't want the string to be terminated prematurely. */
                            if (RT_LIKELY(b != 0)) { /* likely */ }
                            else return VERR_URI_ESCAPED_ZERO;

                            /* Check that we're not expecting more UTF-8 bytes. */
                            if (RT_LIKELY(cchNeeded == 0)) { /* likely */ }
                            else return VERR_URI_MISSING_UTF8_CONTINUATION_BYTE;
                        }
                        /* Are we waiting UTF-8 bytes? */
                        else if (cchNeeded > 0)
                        {
                            if (RT_LIKELY(!(b & 0x40))) { /* likely */ }
                            else return VERR_URI_INVALID_ESCAPED_UTF8_CONTINUATION_BYTE;

                            szUtf8Seq[cchUtf8Seq++] = (char)b;
                            if (--cchNeeded == 0)
                            {
                                szUtf8Seq[cchUtf8Seq] = '\0';
                                rc = RTStrValidateEncoding(szUtf8Seq);
                                if (RT_FAILURE(rc))
                                    return VERR_URI_ESCAPED_CHARS_NOT_VALID_UTF8;
                                cchUtf8Seq = 0;
                            }
                        }
                        /* Start a new UTF-8 sequence. */
                        else
                        {
                            if ((b & 0xf8) == 0xf0)
                                cchNeeded = 3;
                            else if ((b & 0xf0) == 0xe0)
                                cchNeeded = 2;
                            else if ((b & 0xe0) == 0xc0)
                                cchNeeded = 1;
                            else
                                return VERR_URI_INVALID_ESCAPED_UTF8_LEAD_BYTE;
                            szUtf8Seq[0] = (char)b;
                            cchUtf8Seq = 1;
                        }
                        pchSrc  += 3;
                        cchLeft -= 3;
                    }
                    else
                        return VERR_URI_INVALID_ESCAPE_SEQ;
                }
                else
                    return VERR_URI_INVALID_ESCAPE_SEQ;
            } while (cchLeft > 0 && pchSrc[0] == '%');

            /* Check that we're not expecting more UTF-8 bytes. */
            if (RT_LIKELY(cchNeeded == 0)) { /* likely */ }
            else return VERR_URI_MISSING_UTF8_CONTINUATION_BYTE;

            /* next */
            pchSrc = (const char *)memchr(pchSrc, '%', cchLeft);
        } while (pchSrc);
    }

    pParsed->u32Magic = RTURIPARSED_MAGIC;
    return VINF_SUCCESS;
}
/**
 * Gathers VM statistics and reports them to the host.
 */
static void VBoxServiceVMStatsReport(void)
{
#if defined(RT_OS_WINDOWS)
    SYSTEM_INFO systemInfo;
    PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION pProcInfo;
    MEMORYSTATUSEX memStatus;
    uint32_t cbStruct;
    DWORD    cbReturned;

    Assert(gCtx.pfnGlobalMemoryStatusEx && gCtx.pfnNtQuerySystemInformation);
    if (    !gCtx.pfnGlobalMemoryStatusEx
        ||  !gCtx.pfnNtQuerySystemInformation)
        return;

    /* Clear the report so we don't report garbage should NtQuerySystemInformation
       behave in an unexpected manner. */
    VMMDevReportGuestStats req;
    RT_ZERO(req);

    /* Query and report guest statistics */
    GetSystemInfo(&systemInfo);

    memStatus.dwLength = sizeof(memStatus);
    gCtx.pfnGlobalMemoryStatusEx(&memStatus);

    req.guestStats.u32PageSize          = systemInfo.dwPageSize;
    req.guestStats.u32PhysMemTotal      = (uint32_t)(memStatus.ullTotalPhys / _4K);
    req.guestStats.u32PhysMemAvail      = (uint32_t)(memStatus.ullAvailPhys / _4K);
    /* The current size of the committed memory limit, in bytes. This is physical
       memory plus the size of the page file, minus a small overhead. */
    req.guestStats.u32PageFileSize      = (uint32_t)(memStatus.ullTotalPageFile / _4K) - req.guestStats.u32PhysMemTotal;
    req.guestStats.u32MemoryLoad        = memStatus.dwMemoryLoad;
    req.guestStats.u32StatCaps          = VBOX_GUEST_STAT_PHYS_MEM_TOTAL
                                        | VBOX_GUEST_STAT_PHYS_MEM_AVAIL
                                        | VBOX_GUEST_STAT_PAGE_FILE_SIZE
                                        | VBOX_GUEST_STAT_MEMORY_LOAD;
#ifdef VBOX_WITH_MEMBALLOON
    req.guestStats.u32PhysMemBalloon    = VBoxServiceBalloonQueryPages(_4K);
    req.guestStats.u32StatCaps         |= VBOX_GUEST_STAT_PHYS_MEM_BALLOON;
#else
    req.guestStats.u32PhysMemBalloon    = 0;
#endif

    if (gCtx.pfnGetPerformanceInfo)
    {
        PERFORMANCE_INFORMATION perfInfo;

        if (gCtx.pfnGetPerformanceInfo(&perfInfo, sizeof(perfInfo)))
        {
            req.guestStats.u32Processes         = perfInfo.ProcessCount;
            req.guestStats.u32Threads           = perfInfo.ThreadCount;
            req.guestStats.u32Handles           = perfInfo.HandleCount;
            req.guestStats.u32MemCommitTotal    = perfInfo.CommitTotal;     /* already in pages */
            req.guestStats.u32MemKernelTotal    = perfInfo.KernelTotal;     /* already in pages */
            req.guestStats.u32MemKernelPaged    = perfInfo.KernelPaged;     /* already in pages */
            req.guestStats.u32MemKernelNonPaged = perfInfo.KernelNonpaged;  /* already in pages */
            req.guestStats.u32MemSystemCache    = perfInfo.SystemCache;     /* already in pages */
            req.guestStats.u32StatCaps |= VBOX_GUEST_STAT_PROCESSES | VBOX_GUEST_STAT_THREADS | VBOX_GUEST_STAT_HANDLES
                                        | VBOX_GUEST_STAT_MEM_COMMIT_TOTAL | VBOX_GUEST_STAT_MEM_KERNEL_TOTAL
                                        | VBOX_GUEST_STAT_MEM_KERNEL_PAGED | VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED
                                        | VBOX_GUEST_STAT_MEM_SYSTEM_CACHE;
        }
        else
            VBoxServiceVerbose(3, "VBoxServiceVMStatsReport: GetPerformanceInfo failed with %d\n", GetLastError());
    }

    /* Query CPU load information */
    cbStruct = systemInfo.dwNumberOfProcessors * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
    pProcInfo = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)RTMemAlloc(cbStruct);
    if (!pProcInfo)
        return;

    /* Unfortunately GetSystemTimes is XP SP1 and up only, so we need to use the semi-undocumented NtQuerySystemInformation */
    NTSTATUS rc = gCtx.pfnNtQuerySystemInformation(SystemProcessorPerformanceInformation, pProcInfo, cbStruct, &cbReturned);
    if (    !rc
        &&  cbReturned == cbStruct)
    {
        if (gCtx.au64LastCpuLoad_Kernel == 0)
        {
            /* first time */
            gCtx.au64LastCpuLoad_Idle[0]    = pProcInfo->IdleTime.QuadPart;
            gCtx.au64LastCpuLoad_Kernel[0]  = pProcInfo->KernelTime.QuadPart;
            gCtx.au64LastCpuLoad_User[0]    = pProcInfo->UserTime.QuadPart;

            Sleep(250);

            rc = gCtx.pfnNtQuerySystemInformation(SystemProcessorPerformanceInformation, pProcInfo, cbStruct, &cbReturned);
            Assert(!rc);
        }

        uint64_t deltaIdle    = (pProcInfo->IdleTime.QuadPart   - gCtx.au64LastCpuLoad_Idle[0]);
        uint64_t deltaKernel  = (pProcInfo->KernelTime.QuadPart - gCtx.au64LastCpuLoad_Kernel[0]);
        uint64_t deltaUser    = (pProcInfo->UserTime.QuadPart   - gCtx.au64LastCpuLoad_User[0]);
        deltaKernel          -= deltaIdle;  /* idle time is added to kernel time */
        uint64_t ullTotalTime = deltaIdle + deltaKernel + deltaUser;
        if (ullTotalTime == 0) /* Prevent division through zero. */
            ullTotalTime = 1;

        req.guestStats.u32CpuLoad_Idle      = (uint32_t)(deltaIdle  * 100 / ullTotalTime);
        req.guestStats.u32CpuLoad_Kernel    = (uint32_t)(deltaKernel* 100 / ullTotalTime);
        req.guestStats.u32CpuLoad_User      = (uint32_t)(deltaUser  * 100 / ullTotalTime);

        req.guestStats.u32StatCaps |= VBOX_GUEST_STAT_CPU_LOAD_IDLE | VBOX_GUEST_STAT_CPU_LOAD_KERNEL | VBOX_GUEST_STAT_CPU_LOAD_USER;

        gCtx.au64LastCpuLoad_Idle[0]   = pProcInfo->IdleTime.QuadPart;
        gCtx.au64LastCpuLoad_Kernel[0] = pProcInfo->KernelTime.QuadPart;
        gCtx.au64LastCpuLoad_User[0]   = pProcInfo->UserTime.QuadPart;
        /** @todo SMP: report details for each CPU?  */
    }

    for (uint32_t i = 0; i < systemInfo.dwNumberOfProcessors; i++)
    {
        req.guestStats.u32CpuId = i;

        rc = VbglR3StatReport(&req);
        if (RT_SUCCESS(rc))
            VBoxServiceVerbose(3, "VBoxStatsReportStatistics: new statistics (CPU %u) reported successfully!\n", i);
        else
            VBoxServiceVerbose(3, "VBoxStatsReportStatistics: DeviceIoControl (stats report) failed with %d\n", GetLastError());
    }

    RTMemFree(pProcInfo);

#elif defined(RT_OS_LINUX)
    VMMDevReportGuestStats req;
    RT_ZERO(req);
    PRTSTREAM pStrm;
    char szLine[256];
    char *psz;

    int rc = RTStrmOpen("/proc/meminfo", "r", &pStrm);
    if (RT_SUCCESS(rc))
    {
        uint64_t u64Kb;
        uint64_t u64Total = 0, u64Free = 0, u64Buffers = 0, u64Cached = 0, u64PagedTotal = 0;
        for (;;)
        {
            rc = RTStrmGetLine(pStrm, szLine, sizeof(szLine));
            if (RT_FAILURE(rc))
                break;
            if (strstr(szLine, "MemTotal:") == szLine)
            {
                rc = RTStrToUInt64Ex(RTStrStripL(&szLine[9]), &psz, 0, &u64Kb);
                if (RT_SUCCESS(rc))
                    u64Total = u64Kb * _1K;
            }
            else if (strstr(szLine, "MemFree:") == szLine)
            {
                rc = RTStrToUInt64Ex(RTStrStripL(&szLine[8]), &psz, 0, &u64Kb);
                if (RT_SUCCESS(rc))
                    u64Free = u64Kb * _1K;
            }
            else if (strstr(szLine, "Buffers:") == szLine)
            {
                rc = RTStrToUInt64Ex(RTStrStripL(&szLine[8]), &psz, 0, &u64Kb);
                if (RT_SUCCESS(rc))
                    u64Buffers = u64Kb * _1K;
            }
            else if (strstr(szLine, "Cached:") == szLine)
            {
                rc = RTStrToUInt64Ex(RTStrStripL(&szLine[7]), &psz, 0, &u64Kb);
                if (RT_SUCCESS(rc))
                    u64Cached = u64Kb * _1K;
            }
            else if (strstr(szLine, "SwapTotal:") == szLine)
            {
                rc = RTStrToUInt64Ex(RTStrStripL(&szLine[10]), &psz, 0, &u64Kb);
                if (RT_SUCCESS(rc))
                    u64PagedTotal = u64Kb * _1K;
            }
        }
        req.guestStats.u32PhysMemTotal   = u64Total / _4K;
        req.guestStats.u32PhysMemAvail   = (u64Free + u64Buffers + u64Cached) / _4K;
        req.guestStats.u32MemSystemCache = (u64Buffers + u64Cached) / _4K;
        req.guestStats.u32PageFileSize   = u64PagedTotal / _4K;
        RTStrmClose(pStrm);
    }
    else
        VBoxServiceVerbose(3, "VBoxStatsReportStatistics: memory info not available!\n");

    req.guestStats.u32PageSize = getpagesize();
    req.guestStats.u32StatCaps  = VBOX_GUEST_STAT_PHYS_MEM_TOTAL
                                | VBOX_GUEST_STAT_PHYS_MEM_AVAIL
                                | VBOX_GUEST_STAT_MEM_SYSTEM_CACHE
                                | VBOX_GUEST_STAT_PAGE_FILE_SIZE;
#ifdef VBOX_WITH_MEMBALLOON
    req.guestStats.u32PhysMemBalloon  = VBoxServiceBalloonQueryPages(_4K);
    req.guestStats.u32StatCaps       |= VBOX_GUEST_STAT_PHYS_MEM_BALLOON;
#else
    req.guestStats.u32PhysMemBalloon  = 0;
#endif


    /** @todo req.guestStats.u32Threads */
    /** @todo req.guestStats.u32Processes */
    /* req.guestStats.u32Handles doesn't make sense here. */
    /** @todo req.guestStats.u32MemoryLoad */
    /** @todo req.guestStats.u32MemCommitTotal */
    /** @todo req.guestStats.u32MemKernelTotal */
    /** @todo req.guestStats.u32MemKernelPaged, make any sense?  = u32MemKernelTotal? */
    /** @todo req.guestStats.u32MemKernelNonPaged, make any sense? = 0? */

    bool fCpuInfoAvail = false;
    rc = RTStrmOpen("/proc/stat", "r", &pStrm);
    if (RT_SUCCESS(rc))
    {
        for (;;)
        {
            rc = RTStrmGetLine(pStrm, szLine, sizeof(szLine));
            if (RT_FAILURE(rc))
                break;
            if (   strstr(szLine, "cpu") == szLine
                && strlen(szLine) > 3
                && RT_C_IS_DIGIT(szLine[3]))
            {
                uint32_t u32CpuId;
                rc = RTStrToUInt32Ex(&szLine[3], &psz, 0, &u32CpuId);
                if (u32CpuId < VMM_MAX_CPU_COUNT)
                {
                    uint64_t u64User = 0;
                    if (RT_SUCCESS(rc))
                        rc = RTStrToUInt64Ex(RTStrStripL(psz), &psz, 0, &u64User);

                    uint64_t u64Nice = 0;
                    if (RT_SUCCESS(rc))
                        rc = RTStrToUInt64Ex(RTStrStripL(psz), &psz, 0, &u64Nice);

                    uint64_t u64System = 0;
                    if (RT_SUCCESS(rc))
                        rc = RTStrToUInt64Ex(RTStrStripL(psz), &psz, 0, &u64System);

                    uint64_t u64Idle = 0;
                    if (RT_SUCCESS(rc))
                        rc = RTStrToUInt64Ex(RTStrStripL(psz), &psz, 0, &u64Idle);

                    uint64_t u64DeltaIdle   = u64Idle   - gCtx.au64LastCpuLoad_Idle[u32CpuId];
                    uint64_t u64DeltaSystem = u64System - gCtx.au64LastCpuLoad_Kernel[u32CpuId];
                    uint64_t u64DeltaUser   = u64User   - gCtx.au64LastCpuLoad_User[u32CpuId];
                    uint64_t u64DeltaNice   = u64Nice   - gCtx.au64LastCpuLoad_Nice[u32CpuId];

                    uint64_t u64DeltaAll    = u64DeltaIdle
                                            + u64DeltaSystem
                                            + u64DeltaUser
                                            + u64DeltaNice;
                    if (u64DeltaAll == 0) /* Prevent division through zero. */
                        u64DeltaAll = 1;

                    gCtx.au64LastCpuLoad_Idle[u32CpuId]   = u64Idle;
                    gCtx.au64LastCpuLoad_Kernel[u32CpuId] = u64System;
                    gCtx.au64LastCpuLoad_User[u32CpuId]   = u64User;
                    gCtx.au64LastCpuLoad_Nice[u32CpuId]   = u64Nice;

                    req.guestStats.u32CpuId = u32CpuId;
                    req.guestStats.u32CpuLoad_Idle   = (uint32_t)(u64DeltaIdle   * 100 / u64DeltaAll);
                    req.guestStats.u32CpuLoad_Kernel = (uint32_t)(u64DeltaSystem * 100 / u64DeltaAll);
                    req.guestStats.u32CpuLoad_User   = (uint32_t)((u64DeltaUser
                                                                 + u64DeltaNice) * 100 / u64DeltaAll);
                    req.guestStats.u32StatCaps |= VBOX_GUEST_STAT_CPU_LOAD_IDLE
                                               |  VBOX_GUEST_STAT_CPU_LOAD_KERNEL
                                               |  VBOX_GUEST_STAT_CPU_LOAD_USER;
                    fCpuInfoAvail = true;
                    rc = VbglR3StatReport(&req);
                    if (RT_SUCCESS(rc))
                        VBoxServiceVerbose(3, "VBoxStatsReportStatistics: new statistics (CPU %u) reported successfully!\n", u32CpuId);
                    else
                        VBoxServiceVerbose(3, "VBoxStatsReportStatistics: stats report failed with rc=%Rrc\n", rc);
                }
                else
                    VBoxServiceVerbose(3, "VBoxStatsReportStatistics: skipping information for CPU%u\n", u32CpuId);
            }
        }
        RTStrmClose(pStrm);
    }
    if (!fCpuInfoAvail)
    {
        VBoxServiceVerbose(3, "VBoxStatsReportStatistics: CPU info not available!\n");
        rc = VbglR3StatReport(&req);
        if (RT_SUCCESS(rc))
            VBoxServiceVerbose(3, "VBoxStatsReportStatistics: new statistics reported successfully!\n");
        else
            VBoxServiceVerbose(3, "VBoxStatsReportStatistics: stats report failed with rc=%Rrc\n", rc);
    }

#elif defined(RT_OS_SOLARIS)
    VMMDevReportGuestStats req;
    RT_ZERO(req);
    kstat_ctl_t *pStatKern = kstat_open();
    if (pStatKern)
    {
        /*
         * Memory statistics.
         */
        uint64_t u64Total = 0, u64Free = 0, u64Buffers = 0, u64Cached = 0, u64PagedTotal = 0;
        int rc = -1;
        kstat_t *pStatPages = kstat_lookup(pStatKern, (char *)"unix", 0 /* instance */, (char *)"system_pages");
        if (pStatPages)
        {
            rc = kstat_read(pStatKern, pStatPages, NULL /* optional-copy-buf */);
            if (rc != -1)
            {
                kstat_named_t *pStat = NULL;
                pStat = (kstat_named_t *)kstat_data_lookup(pStatPages, (char *)"pagestotal");
                if (pStat)
                    u64Total = pStat->value.ul;

                pStat = (kstat_named_t *)kstat_data_lookup(pStatPages, (char *)"freemem");
                if (pStat)
                    u64Free = pStat->value.ul;
            }
        }

        kstat_t *pStatZFS = kstat_lookup(pStatKern, (char *)"zfs", 0 /* instance */, (char *)"arcstats");
        if (pStatZFS)
        {
            rc = kstat_read(pStatKern, pStatZFS, NULL /* optional-copy-buf */);
            if (rc != -1)
            {
                kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(pStatZFS, (char *)"size");
                if (pStat)
                    u64Cached = pStat->value.ul;
            }
        }

        /*
         * The vminfo are accumulative counters updated every "N" ticks. Let's get the
         * number of stat updates so far and use that to divide the swap counter.
         */
        kstat_t *pStatInfo = kstat_lookup(pStatKern, (char *)"unix", 0 /* instance */, (char *)"sysinfo");
        if (pStatInfo)
        {
            sysinfo_t SysInfo;
            rc = kstat_read(pStatKern, pStatInfo, &SysInfo);
            if (rc != -1)
            {
                kstat_t *pStatVMInfo = kstat_lookup(pStatKern, (char *)"unix", 0 /* instance */, (char *)"vminfo");
                if (pStatVMInfo)
                {
                    vminfo_t VMInfo;
                    rc = kstat_read(pStatKern, pStatVMInfo, &VMInfo);
                    if (rc != -1)
                    {
                        Assert(SysInfo.updates != 0);
                        u64PagedTotal = VMInfo.swap_avail / SysInfo.updates;
                    }
                }
            }
        }

        req.guestStats.u32PhysMemTotal   = u64Total;        /* already in pages */
        req.guestStats.u32PhysMemAvail   = u64Free;         /* already in pages */
        req.guestStats.u32MemSystemCache = u64Cached / _4K;
        req.guestStats.u32PageFileSize   = u64PagedTotal;   /* already in pages */
        /** @todo req.guestStats.u32Threads */
        /** @todo req.guestStats.u32Processes */
        /** @todo req.guestStats.u32Handles -- ??? */
        /** @todo req.guestStats.u32MemoryLoad */
        /** @todo req.guestStats.u32MemCommitTotal */
        /** @todo req.guestStats.u32MemKernelTotal */
        /** @todo req.guestStats.u32MemKernelPaged */
        /** @todo req.guestStats.u32MemKernelNonPaged */
        req.guestStats.u32PageSize = getpagesize();

        req.guestStats.u32StatCaps = VBOX_GUEST_STAT_PHYS_MEM_TOTAL
                                   | VBOX_GUEST_STAT_PHYS_MEM_AVAIL
                                   | VBOX_GUEST_STAT_MEM_SYSTEM_CACHE
                                   | VBOX_GUEST_STAT_PAGE_FILE_SIZE;
#ifdef VBOX_WITH_MEMBALLOON
        req.guestStats.u32PhysMemBalloon  = VBoxServiceBalloonQueryPages(_4K);
        req.guestStats.u32StatCaps       |= VBOX_GUEST_STAT_PHYS_MEM_BALLOON;
#else
        req.guestStats.u32PhysMemBalloon  = 0;
#endif

        /*
         * CPU statistics.
         */
        cpu_stat_t StatCPU;
        RT_ZERO(StatCPU);
        kstat_t *pStatNode = NULL;
        uint32_t cCPUs = 0;
        bool fCpuInfoAvail = false;
        for (pStatNode = pStatKern->kc_chain; pStatNode != NULL; pStatNode = pStatNode->ks_next)
        {
            if (!strcmp(pStatNode->ks_module, "cpu_stat"))
            {
                rc = kstat_read(pStatKern, pStatNode, &StatCPU);
                if (rc == -1)
                    break;

                uint64_t u64Idle   = StatCPU.cpu_sysinfo.cpu[CPU_IDLE];
                uint64_t u64User   = StatCPU.cpu_sysinfo.cpu[CPU_USER];
                uint64_t u64System = StatCPU.cpu_sysinfo.cpu[CPU_KERNEL];

                uint64_t u64DeltaIdle   = u64Idle   - gCtx.au64LastCpuLoad_Idle[cCPUs];
                uint64_t u64DeltaSystem = u64System - gCtx.au64LastCpuLoad_Kernel[cCPUs];
                uint64_t u64DeltaUser   = u64User   - gCtx.au64LastCpuLoad_User[cCPUs];

                uint64_t u64DeltaAll    = u64DeltaIdle + u64DeltaSystem + u64DeltaUser;
                if (u64DeltaAll == 0) /* Prevent division through zero. */
                    u64DeltaAll = 1;

                gCtx.au64LastCpuLoad_Idle[cCPUs]   = u64Idle;
                gCtx.au64LastCpuLoad_Kernel[cCPUs] = u64System;
                gCtx.au64LastCpuLoad_User[cCPUs]   = u64User;

                req.guestStats.u32CpuId = cCPUs;
                req.guestStats.u32CpuLoad_Idle   = (uint32_t)(u64DeltaIdle   * 100 / u64DeltaAll);
                req.guestStats.u32CpuLoad_Kernel = (uint32_t)(u64DeltaSystem * 100 / u64DeltaAll);
                req.guestStats.u32CpuLoad_User   = (uint32_t)(u64DeltaUser   * 100 / u64DeltaAll);

                req.guestStats.u32StatCaps |= VBOX_GUEST_STAT_CPU_LOAD_IDLE
                                           |  VBOX_GUEST_STAT_CPU_LOAD_KERNEL
                                           |  VBOX_GUEST_STAT_CPU_LOAD_USER;
                fCpuInfoAvail = true;

                rc = VbglR3StatReport(&req);
                if (RT_SUCCESS(rc))
                    VBoxServiceVerbose(3, "VBoxStatsReportStatistics: new statistics (CPU %u) reported successfully!\n", cCPUs);
                else
                    VBoxServiceVerbose(3, "VBoxStatsReportStatistics: stats report failed with rc=%Rrc\n", rc);
                cCPUs++;
            }
        }

        /*
         * Report whatever statistics were collected.
         */
        if (!fCpuInfoAvail)
        {
            VBoxServiceVerbose(3, "VBoxStatsReportStatistics: CPU info not available!\n");
            rc = VbglR3StatReport(&req);
            if (RT_SUCCESS(rc))
                VBoxServiceVerbose(3, "VBoxStatsReportStatistics: new statistics reported successfully!\n");
            else
                VBoxServiceVerbose(3, "VBoxStatsReportStatistics: stats report failed with rc=%Rrc\n", rc);
        }

        kstat_close(pStatKern);
    }

#else
    /* todo: implement for other platforms. */

#endif
}
Example #21
0
/**
 * Parses a out the next block from a version string.
 *
 * @returns true if numeric, false if not.
 * @param   ppszVer             The string cursor, IN/OUT.
 * @param   pi32Value           Where to return the value if numeric.
 * @param   pcchBlock           Where to return the block length.
 */
static bool rtStrVersionParseBlock(const char **ppszVer, int32_t *pi32Value, size_t *pcchBlock)
{
    const char *psz = *ppszVer;

    /*
     * Check for end-of-string.
     */
    if (!*psz)
    {
        *pi32Value = 0;
        *pcchBlock = 0;
        return false;
    }

    /*
     * Try convert the block to a number the simple way.
     */
    char ch;
    bool fNumeric = RT_C_IS_DIGIT(*psz);
    if (fNumeric)
    {
        do
            ch = *++psz;
        while (ch && RT_C_IS_DIGIT(ch));

        int rc = RTStrToInt32Ex(*ppszVer, NULL, 10, pi32Value);
        if (RT_FAILURE(rc) || rc == VWRN_NUMBER_TOO_BIG)
        {
            AssertRC(rc);
            fNumeric = false;
            *pi32Value = 0;
        }
    }
    else
    {
        /*
         * Find the end of the current string.  Make a special case for SVN
         * revision numbers that immediately follows a release tag string.
         */
        do
            ch = *++psz;
        while (    ch
                   && !RT_C_IS_DIGIT(ch)
                   && !RTSTRVER_IS_PUNCTUACTION(ch));

        size_t cchBlock = psz - *ppszVer;
        if (   cchBlock > 1
                && psz[-1] == 'r'
                && RT_C_IS_DIGIT(*psz))
        {
            psz--;
            cchBlock--;
        }


        /*
         * Translate standard pre release terms to negative values.
         */
        static const struct
        {
            size_t      cch;
            const char *psz;
            int32_t     iValue;
        } s_aTerms[] =
        {
            { 2, "RC",      -100000 },
            { 3, "PRE",     -200000 },
            { 5, "GAMMA",   -300000 },
            { 4, "BETA",    -400000 },
            { 5, "ALPHA",   -500000 }
        };

        int32_t iVal1 = 0;
        for (unsigned i = 0; i < RT_ELEMENTS(s_aTerms); i++)
            if (   cchBlock == s_aTerms[i].cch
                    && !RTStrNCmp(s_aTerms[i].psz, *ppszVer, cchBlock))
            {
                iVal1 = s_aTerms[i].iValue;
                break;
            }
        if (iVal1 != 0)
        {
            /*
             * Does the prelease term have a trailing number?
             * Add it assuming BETA == BETA1.
             */
            if (RT_C_IS_DIGIT(*psz))
            {
                const char *psz2 = psz;
                do
                    ch = *++psz;
                while (   ch
                          && RT_C_IS_DIGIT(ch)
                          && !RTSTRVER_IS_PUNCTUACTION(ch));

                int rc = RTStrToInt32Ex(psz2, NULL, 10, pi32Value);
                if (RT_SUCCESS(rc) && rc != VWRN_NUMBER_TOO_BIG && *pi32Value)
                    iVal1 += *pi32Value - 1;
                else
                {
                    AssertRC(rc);
                    psz = psz2;
                }
            }
            fNumeric = true;
        }
        *pi32Value = iVal1;
    }
    *pcchBlock = psz - *ppszVer;

    /*
     * Skip trailing punctuation.
     */
    if (RTSTRVER_IS_PUNCTUACTION(*psz))
        psz++;
    *ppszVer = psz;

    return fNumeric;
}