Beispiel #1
0
static char *MyGetNextSignificantLine(PRTSTREAM pFile, char *pszBuf, size_t cbBuf, uint32_t *piLine, int *prc)
{
    for (;;)
    {
        *pszBuf = '\0';
        int rc = RTStrmGetLine(pFile, pszBuf, cbBuf);
        if (RT_FAILURE(rc))
        {
            if (rc != VERR_EOF)
            {
                Error("Read error: %Rrc", rc);
                *prc = rc;
                return NULL;
            }
            if (!*pszBuf)
                return NULL;
        }
        *piLine += 1;

        /* Significant? */
        char *pszStart = RTStrStrip(pszBuf);
        if (*pszStart && *pszStart != '#')
            return pszStart;
    }
}
Beispiel #2
0
/**
 * Executes the VMMDEV_TESTING_CMD_VALUE_REG command when the data is ready.
 *
 * @param   pDevIns             The PDM device instance.
 * @param   pThis               The instance VMMDev data.
 */
static void vmmdevTestingCmdExec_ValueReg(PPDMDEVINS pDevIns, VMMDevState *pThis)
{
    char *pszRegNm = strchr(pThis->TestingData.String.sz, ':');
    if (pszRegNm)
    {
        *pszRegNm++ = '\0';
        pszRegNm = RTStrStrip(pszRegNm);
    }
    char        *pszValueNm = RTStrStrip(pThis->TestingData.String.sz);
    size_t const cchValueNm = strlen(pszValueNm);
    if (cchValueNm && pszRegNm && *pszRegNm)
    {
        PUVM        pUVM  = PDMDevHlpGetUVM(pDevIns);
        PVM         pVM   = PDMDevHlpGetVM(pDevIns);
        VMCPUID     idCpu = VMMGetCpuId(pVM);
        uint64_t    u64Value;
        int rc2 = DBGFR3RegNmQueryU64(pUVM, idCpu, pszRegNm, &u64Value);
        if (RT_SUCCESS(rc2))
        {
            const char *pszWarn = rc2 == VINF_DBGF_TRUNCATED_REGISTER ? " truncated" : "";
#if 1 /*!RTTestValue format*/
            char szFormat[128], szValue[128];
            RTStrPrintf(szFormat, sizeof(szFormat), "%%VR{%s}", pszRegNm);
            rc2 = DBGFR3RegPrintf(pUVM, idCpu, szValue, sizeof(szValue), szFormat);
            if (RT_SUCCESS(rc2))
                VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %16s {reg=%s}%s\n",
                                       pszValueNm,
                                       (ssize_t)cchValueNm - 12 > 48 ? 0 : 48 - ((ssize_t)cchValueNm - 12), "",
                                       szValue, pszRegNm, pszWarn));
            else
#endif
                VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %'9llu (%#llx) [0] {reg=%s}%s\n",
                                       pszValueNm,
                                       (ssize_t)cchValueNm - 12 > 48 ? 0 : 48 - ((ssize_t)cchValueNm - 12), "",
                                       u64Value, u64Value, pszRegNm, pszWarn));
        }
        else
            VMMDEV_TESTING_OUTPUT(("testing: error querying register '%s' for value '%s': %Rrc\n",
                                   pszRegNm, pszValueNm, rc2));
    }
    else
        VMMDEV_TESTING_OUTPUT(("testing: malformed register value '%s'/'%s'\n", pszValueNm, pszRegNm));
}
RTDECL(int) RTMpGetDescription(RTCPUID idCpu, char *pszBuf, size_t cbBuf)
{
    /*
     * Check that the specified cpu is valid & online.
     */
    if (idCpu != NIL_RTCPUID && !RTMpIsCpuOnline(idCpu))
        return RTMpIsCpuPossible(idCpu)
             ? VERR_CPU_OFFLINE
             : VERR_CPU_NOT_FOUND;

    /*
     * Construct the description string in a temporary buffer.
     */
    char        szString[4*4*3+1];
    RT_ZERO(szString);
#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
    if (!ASMHasCpuId())
        return rtMpGetDescriptionUnknown(pszBuf, cbBuf);

    uint32_t    uMax;
    uint32_t    uEBX, uECX, uEDX;
    ASMCpuId(0x80000000, &uMax, &uEBX, &uECX, &uEDX);
    if (uMax >= 0x80000002)
    {
        ASMCpuId(0x80000002,     &szString[0  + 0], &szString[0  + 4], &szString[0  + 8], &szString[0  + 12]);
        if (uMax >= 0x80000003)
            ASMCpuId(0x80000003, &szString[16 + 0], &szString[16 + 4], &szString[16 + 8], &szString[16 + 12]);
        if (uMax >= 0x80000004)
            ASMCpuId(0x80000004, &szString[32 + 0], &szString[32 + 4], &szString[32 + 8], &szString[32 + 12]);
    }
    else
    {
        ASMCpuId(0x00000000, &uMax, &uEBX, &uECX, &uEDX);
        ((uint32_t *)&szString[0])[0] = uEBX;
        ((uint32_t *)&szString[0])[1] = uEDX;
        ((uint32_t *)&szString[0])[2] = uECX;
    }

#else
# error "PORTME or use RTMpGetDescription-generic-stub.cpp."
#endif

    /*
     * Copy it out into the buffer supplied by the caller.
     */
    char   *pszSrc = RTStrStrip(szString);
    size_t  cchSrc = strlen(pszSrc);
    if (cchSrc >= cbBuf)
        return VERR_BUFFER_OVERFLOW;
    memcpy(pszBuf, pszSrc, cchSrc + 1);
    return VINF_SUCCESS;
}
/**
 * Reads an ACK or NACK.
 *
 * @returns S_OK on ACK, E_FAIL+setError() on failure or NACK.
 * @param   pState              The teleporter source state.
 * @param   pszWhich            Which ACK is this this?
 * @param   pszNAckMsg          Optional NACK message.
 *
 * @remarks the setError laziness forces this to be a Console member.
 */
HRESULT
Console::teleporterSrcReadACK(TeleporterStateSrc *pState, const char *pszWhich,
                              const char *pszNAckMsg /*= NULL*/)
{
    char szMsg[256];
    int vrc = teleporterTcpReadLine(pState, szMsg, sizeof(szMsg));
    if (RT_FAILURE(vrc))
        return setError(E_FAIL, tr("Failed reading ACK(%s): %Rrc"), pszWhich, vrc);

    if (!strcmp(szMsg, "ACK"))
        return S_OK;

    if (!strncmp(szMsg, "NACK=", sizeof("NACK=") - 1))
    {
        char *pszMsgText = strchr(szMsg, ';');
        if (pszMsgText)
            *pszMsgText++ = '\0';

        int32_t vrc2;
        vrc = RTStrToInt32Full(&szMsg[sizeof("NACK=") - 1], 10, &vrc2);
        if (vrc == VINF_SUCCESS)
        {
            /*
             * Well formed NACK, transform it into an error.
             */
            if (pszNAckMsg)
            {
                LogRel(("Teleporter: %s: NACK=%Rrc (%d)\n", pszWhich, vrc2, vrc2));
                return setError(E_FAIL, pszNAckMsg);
            }

            if (pszMsgText)
            {
                pszMsgText = RTStrStrip(pszMsgText);
                for (size_t off = 0; pszMsgText[off]; off++)
                    if (pszMsgText[off] == '\r')
                        pszMsgText[off] = '\n';

                LogRel(("Teleporter: %s: NACK=%Rrc (%d) - '%s'\n", pszWhich, vrc2, vrc2, pszMsgText));
                if (strlen(pszMsgText) > 4)
                    return setError(E_FAIL, "%s", pszMsgText);
                return setError(E_FAIL, "NACK(%s) - %Rrc (%d) '%s'", pszWhich, vrc2, vrc2, pszMsgText);
            }

            return setError(E_FAIL, "NACK(%s) - %Rrc (%d)", pszWhich, vrc2, vrc2);
        }

        if (pszMsgText)
            pszMsgText[-1] = ';';
    }
    return setError(E_FAIL, tr("%s: Expected ACK or NACK, got '%s'"), pszWhich, szMsg);
}
Beispiel #5
0
/** Print the CPU name, if available. */
static RTEXITCODE handlerCpuName(int argc, char **argv)
{
    NOREF(argc); NOREF(argv);

    char szTmp[1024];
    int rc = RTMpGetDescription(NIL_RTCPUID, szTmp, sizeof(szTmp));
    if (RT_SUCCESS(rc))
    {
        int cch = RTPrintf("%s\n", RTStrStrip(szTmp));
        return cch > 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    }
    return RTEXITCODE_FAILURE;
}
Beispiel #6
0
/**
 * Finds the svn binary, updating g_szSvnPath and g_enmSvnVersion.
 */
static void scmSvnFindSvnBinary(PSCMRWSTATE pState)
{
    /* Already been called? */
    if (g_szSvnPath[0] != '\0')
        return;

    /*
     * Locate it.
     */
    /** @todo code page fun... */
#ifdef RT_OS_WINDOWS
    const char *pszEnvVar = RTEnvGet("Path");
#else
    const char *pszEnvVar = RTEnvGet("PATH");
#endif
    if (pszEnvVar)
    {
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
        int rc = RTPathTraverseList(pszEnvVar, ';', scmSvnFindSvnBinaryCallback, g_szSvnPath, (void *)sizeof(g_szSvnPath));
#else
        int rc = RTPathTraverseList(pszEnvVar, ':', scmSvnFindSvnBinaryCallback, g_szSvnPath, (void *)sizeof(g_szSvnPath));
#endif
        if (RT_FAILURE(rc))
            strcpy(g_szSvnPath, "svn");
    }
    else
        strcpy(g_szSvnPath, "svn");

    /*
     * Check the version.
     */
    const char *apszArgs[] = { g_szSvnPath, "--version", "--quiet", NULL };
    char *pszVersion;
    int rc = scmSvnRunAndGetOutput(pState, apszArgs, false, &pszVersion);
    if (RT_SUCCESS(rc))
    {
        char *pszStripped = RTStrStrip(pszVersion);
        if (RTStrVersionCompare(pszVersion, "1.7") >= 0)
            g_enmSvnVersion = kScmSvnVersion_1_7;
        else if (RTStrVersionCompare(pszVersion, "1.6") >= 0)
            g_enmSvnVersion = kScmSvnVersion_1_6;
        else
            g_enmSvnVersion = kScmSvnVersion_Ancient;
        RTStrFree(pszVersion);
    }
    else
        g_enmSvnVersion = kScmSvnVersion_Ancient;
}
/**
 * Init once for the path conversion code.
 *
 * @returns IPRT status code.
 * @param   pvUser1             Unused.
 * @param   pvUser2             Unused.
 */
static DECLCALLBACK(int32_t) rtPathConvInitOnce(void *pvUser)
{
    /*
     * Read the environment variable, no mercy on misconfigs here except that
     * empty values are quietly ignored.  (We use a temp buffer for stripping.)
     */
    char *pszEnvValue = NULL;
    char  szEnvValue[sizeof(g_szFsCodeset)];
    int rc = RTEnvGetEx(RTENV_DEFAULT, RTPATH_CODESET_ENV_VAR, szEnvValue, sizeof(szEnvValue), NULL);
    if (rc != VERR_ENV_VAR_NOT_FOUND && RT_FAILURE(rc))
        return rc;
    if (RT_SUCCESS(rc))
        pszEnvValue = RTStrStrip(szEnvValue);

    if (pszEnvValue && *pszEnvValue)
    {
        g_fPassthruUtf8  = rtPathConvInitIsUtf8(pszEnvValue);
        g_enmFsToUtf8Idx = RTSTRICONV_FS_TO_UTF8;
        g_enmUtf8ToFsIdx = RTSTRICONV_UTF8_TO_FS;
        strcpy(g_szFsCodeset, pszEnvValue);
    }
    else
    {
        const char *pszCodeset = rtStrGetLocaleCodeset();
        size_t      cchCodeset = pszCodeset ? strlen(pszCodeset) : sizeof(g_szFsCodeset);
        if (cchCodeset >= sizeof(g_szFsCodeset))
            /* This shouldn't happen, but we'll manage. */
            g_szFsCodeset[0] = '\0';
        else
        {
            memcpy(g_szFsCodeset, pszCodeset, cchCodeset + 1);
            pszCodeset = g_szFsCodeset;
        }
        g_fPassthruUtf8  = rtPathConvInitIsUtf8(pszCodeset);
        g_enmFsToUtf8Idx = RTSTRICONV_LOCALE_TO_UTF8;
        g_enmUtf8ToFsIdx = RTSTRICONV_UTF8_TO_LOCALE;
    }

    NOREF(pvUser);
    return VINF_SUCCESS;
}
RTDECL(int) RTManifestReadStandardEx(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, char *pszErr, size_t cbErr)
{
    /*
     * Validate input.
     */
    AssertPtrNull(pszErr);
    if (pszErr && cbErr)
        *pszErr = '\0';
    RTMANIFESTINT *pThis = hManifest;
    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE);

    /*
     * Process the stream line by line.
     */
    uint32_t iLine = 0;
    for (;;)
    {
        /*
         * Read a line from the input stream.
         */
        iLine++;
        char szLine[RTPATH_MAX + RTSHA512_DIGEST_LEN + 32];
        int rc = rtManifestReadLine(hVfsIos, szLine, sizeof(szLine));
        if (RT_FAILURE(rc))
        {
            if (rc == VERR_EOF)
                return VINF_SUCCESS;
            RTStrPrintf(pszErr, cbErr, "Error reading line #%u: %Rrc", iLine, rc);
            return rc;
        }
        if (rc != VINF_SUCCESS)
        {
            RTStrPrintf(pszErr, cbErr, "Line number %u is too long", iLine);
            return VERR_OUT_OF_RANGE;
        }

        /*
         * Strip it and skip if empty.
         */
        char *psz = RTStrStrip(szLine);
        if (!*psz)
            continue;

        /*
         * Read the attribute name.
         */
        const char * const pszAttr = psz;
        do
            psz++;
        while (!RT_C_IS_BLANK(*psz) && *psz);
        if (*psz)
            *psz++ = '\0';

        /*
         * The entry name is enclosed in parenthesis and followed by a '='.
         */
        psz = RTStrStripL(psz);
        if (*psz != '(')
        {
            RTStrPrintf(pszErr, cbErr, "Expected '(' after %zu on line %u", psz - szLine, iLine);
            return VERR_PARSE_ERROR;
        }
        const char * const pszName = ++psz;
        while (*psz)
        {
            if (*psz == ')')
            {
                char *psz2 = RTStrStripL(psz + 1);
                if (*psz2 == '=')
                {
                    *psz = '\0';
                    psz = psz2;
                    break;
                }
            }
            psz++;
        }

        if (*psz != '=')
        {
            RTStrPrintf(pszErr, cbErr, "Expected ')=' at %zu on line %u", psz - szLine, iLine);
            return VERR_PARSE_ERROR;
        }

        /*
         * The value.
         */
        psz = RTStrStrip(psz + 1);
        const char * const pszValue = psz;
        if (!*psz)
        {
            RTStrPrintf(pszErr, cbErr, "Expected value at %zu on line %u", psz - szLine, iLine);
            return VERR_PARSE_ERROR;
        }

        /*
         * Detect attribute type and sanity check the value.
         */
        uint32_t fType = RTMANIFEST_ATTR_UNKNOWN;
        static const struct
        {
            const char *pszAttr;
            uint32_t    fType;
            unsigned    cBits;
            unsigned    uBase;
        } s_aDecAttrs[] =
        {
            { "SIZE", RTMANIFEST_ATTR_SIZE, 64,  10}
        };
        for (unsigned i = 0; i < RT_ELEMENTS(s_aDecAttrs); i++)
            if (!strcmp(s_aDecAttrs[i].pszAttr, pszAttr))
            {
                fType = s_aDecAttrs[i].fType;
                rc = RTStrToUInt64Full(pszValue, s_aDecAttrs[i].uBase, NULL);
                if (rc != VINF_SUCCESS)
                {
                    RTStrPrintf(pszErr, cbErr, "Malformed value ('%s') at %zu on line %u: %Rrc", pszValue, psz - szLine, iLine, rc);
                    return VERR_PARSE_ERROR;
                }
                break;
            }

        if (fType == RTMANIFEST_ATTR_UNKNOWN)
        {
            static const struct
            {
                const char *pszAttr;
                uint32_t    fType;
                unsigned    cchHex;
            } s_aHexAttrs[] =
            {
                { "MD5",        RTMANIFEST_ATTR_MD5,        RTMD5_DIGEST_LEN    },
                { "SHA1",       RTMANIFEST_ATTR_SHA1,       RTSHA1_DIGEST_LEN   },
                { "SHA256",     RTMANIFEST_ATTR_SHA256,     RTSHA256_DIGEST_LEN },
                { "SHA512",     RTMANIFEST_ATTR_SHA512,     RTSHA512_DIGEST_LEN }
            };
            for (unsigned i = 0; i < RT_ELEMENTS(s_aHexAttrs); i++)
                if (!strcmp(s_aHexAttrs[i].pszAttr, pszAttr))
                {
                    fType = s_aHexAttrs[i].fType;
                    for (unsigned off = 0; off < s_aHexAttrs[i].cchHex; off++)
                        if (!RT_C_IS_XDIGIT(pszValue[off]))
                        {
                            RTStrPrintf(pszErr, cbErr, "Expected hex digit at %zu on line %u (value '%s', pos %u)",
                                        pszValue - szLine + off, iLine, pszValue, off);
                            return VERR_PARSE_ERROR;
                        }
                    break;
                }
        }

        /*
         * Finally, add it.
         */
        rc = RTManifestEntrySetAttr(hManifest, pszName, pszAttr, pszValue, fType);
        if (RT_FAILURE(rc))
        {
            RTStrPrintf(pszErr, cbErr, "RTManifestEntrySetAttr(,'%s','%s', '%s', %#x) failed on line %u: %Rrc",
                        pszName, pszAttr, pszValue, fType, iLine, rc);
            return rc;
        }
    }
}
Beispiel #9
0
/**
 * Generates a kind of report of the hardware, software and whatever else we
 * think might be useful to know about the testbox.
 */
static RTEXITCODE handlerReport(int argc, char **argv)
{
    NOREF(argc); NOREF(argv);

#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
    /*
     * For now, a simple CPUID dump.  Need to figure out how to share code
     * like this with other bits, putting it in IPRT.
     */
    RTPrintf("CPUID Dump\n"
             "Leaf      eax      ebx      ecx      edx\n"
             "---------------------------------------------\n");
    static uint32_t const s_auRanges[] =
    {
        UINT32_C(0x00000000),
        UINT32_C(0x80000000),
        UINT32_C(0x80860000),
        UINT32_C(0xc0000000),
        UINT32_C(0x40000000),
    };
    for (uint32_t iRange = 0; iRange < RT_ELEMENTS(s_auRanges); iRange++)
    {
        uint32_t const uFirst = s_auRanges[iRange];

        uint32_t uEax, uEbx, uEcx, uEdx;
        ASMCpuIdExSlow(uFirst, 0, 0, 0, &uEax, &uEbx, &uEcx, &uEdx);
        if (uEax >= uFirst && uEax < uFirst + 100)
        {
            uint32_t const cLeafs = RT_MIN(uEax - uFirst + 1, 32);
            for (uint32_t iLeaf = 0; iLeaf < cLeafs; iLeaf++)
            {
                uint32_t uLeaf = uFirst + iLeaf;
                ASMCpuIdExSlow(uLeaf, 0, 0, 0, &uEax, &uEbx, &uEcx, &uEdx);

                /* Clear APIC IDs to avoid submitting new reports all the time. */
                if (uLeaf == 1)
                    uEbx &= UINT32_C(0x00ffffff);
                if (uLeaf == 0xb)
                    uEdx  = 0;
                if (uLeaf == 0x8000001e)
                    uEax  = 0;

                /* Clear some other node/cpu/core/thread ids. */
                if (uLeaf == 0x8000001e)
                {
                    uEbx &= UINT32_C(0xffffff00);
                    uEcx &= UINT32_C(0xffffff00);
                }

                RTPrintf("%08x: %08x %08x %08x %08x\n", uLeaf, uEax, uEbx, uEcx, uEdx);
            }
        }
    }
    RTPrintf("\n");

    /*
     * DMI info.
     */
    RTPrintf("DMI Info\n"
             "--------\n");
    static const struct { const char *pszName; RTSYSDMISTR enmDmiStr; } s_aDmiStrings[] =
    {
        { "Product Name",           RTSYSDMISTR_PRODUCT_NAME },
        { "Product version",        RTSYSDMISTR_PRODUCT_VERSION },
        { "Product UUID",           RTSYSDMISTR_PRODUCT_UUID },
        { "Product Serial",         RTSYSDMISTR_PRODUCT_SERIAL },
        { "System Manufacturer",    RTSYSDMISTR_MANUFACTURER },
    };
    for (uint32_t iDmiString = 0; iDmiString < RT_ELEMENTS(s_aDmiStrings); iDmiString++)
    {
        char szTmp[4096];
        RT_ZERO(szTmp);
        int rc = RTSystemQueryDmiString(s_aDmiStrings[iDmiString].enmDmiStr, szTmp, sizeof(szTmp) - 1);
        if (RT_SUCCESS(rc))
            RTPrintf("%25s: %s\n", s_aDmiStrings[iDmiString].pszName, RTStrStrip(szTmp));
        else
            RTPrintf("%25s: %s [rc=%Rrc]\n", s_aDmiStrings[iDmiString].pszName, RTStrStrip(szTmp), rc);
    }
    RTPrintf("\n");

#else
#endif

    /*
     * Dump the environment.
     */
    RTPrintf("Environment\n"
             "-----------\n");
    RTENV hEnv;
    int rc = RTEnvClone(&hEnv, RTENV_DEFAULT);
    if (RT_SUCCESS(rc))
    {
        uint32_t cVars = RTEnvCountEx(hEnv);
        for (uint32_t iVar = 0; iVar < cVars; iVar++)
        {
            char szVar[1024];
            char szValue[16384];
            rc = RTEnvGetByIndexEx(hEnv, iVar, szVar, sizeof(szVar), szValue, sizeof(szValue));

            /* zap the value of variables that are subject to change. */
            if (   (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW)
                && (   !strcmp(szVar, "TESTBOX_SCRIPT_REV")
                    || !strcmp(szVar, "TESTBOX_ID")
                    || !strcmp(szVar, "TESTBOX_SCRATCH_SIZE")
                    || !strcmp(szVar, "TESTBOX_TIMEOUT")
                    || !strcmp(szVar, "TESTBOX_TIMEOUT_ABS")
                    || !strcmp(szVar, "TESTBOX_TEST_SET_ID")
                   )
               )
               strcpy(szValue, "<volatile>");

            if (RT_SUCCESS(rc))
                RTPrintf("%25s=%s\n", szVar, szValue);
            else if (rc == VERR_BUFFER_OVERFLOW)
                RTPrintf("%25s=%s [VERR_BUFFER_OVERFLOW]\n", szVar, szValue);
            else
                RTPrintf("rc=%Rrc\n", rc);
        }
        RTEnvDestroy(hEnv);
    }

    /** @todo enumerate volumes and whatnot.  */

    int cch = RTPrintf("\n");
    return cch > 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
Beispiel #10
0
RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed)
{
    /* Validate input */
    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
    AssertReturn(cbSize > 0, VERR_INVALID_PARAMETER);
    AssertPtrReturn(paTests, VERR_INVALID_POINTER);
    AssertReturn(cTests > 0, VERR_INVALID_PARAMETER);
    AssertPtrNullReturn(piFailed, VERR_INVALID_POINTER);

    int rc = VINF_SUCCESS;

    PRTMANIFESTFILEENTRY paFiles = (PRTMANIFESTFILEENTRY)RTMemTmpAllocZ(sizeof(RTMANIFESTFILEENTRY) * cTests);
    if (!paFiles)
        return VERR_NO_MEMORY;

    /* Fill our compare list */
    for (size_t i = 0; i < cTests; ++i)
        paFiles[i].pTestPattern = &paTests[i];

    char *pcBuf = (char*)pvBuf;
    size_t cbRead = 0;
    /* Parse the manifest file line by line */
    for (;;)
    {
        if (cbRead >= cbSize)
            break;

        size_t cch = rtManifestIndexOfCharInBuf(pcBuf, cbSize - cbRead, '\n') + 1;

        /* Skip empty lines (UNIX/DOS format) */
        if (   (   cch == 1
                && pcBuf[0] == '\n')
            || (   cch == 2
                && pcBuf[0] == '\r'
                && pcBuf[1] == '\n'))
        {
            pcBuf += cch;
            cbRead += cch;
            continue;
        }

        /** @todo r=bird:
         *  -# Better deal with this EOF line platform dependency
         *  -# The SHA1 and SHA256 tests should probably include a blank space check.
         *  -# If there is a specific order to the elements in the string, it would be
         *     good if the delimiter searching checked for it.
         *  -# Deal with filenames containing delimiter characters.
         */

        /* Check for the digest algorithm */
        if (   cch < 4
            || (   !(   pcBuf[0] == 'S'
                     && pcBuf[1] == 'H'
                     && pcBuf[2] == 'A'
                     && pcBuf[3] == '1')
                &&
                   !(   pcBuf[0] == 'S'
                     && pcBuf[1] == 'H'
                     && pcBuf[2] == 'A'
                     && pcBuf[3] == '2'
                     && pcBuf[4] == '5'
                     && pcBuf[5] == '6')
               )
            )
        {
            /* Digest unsupported */
            rc = VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE;
            break;
        }

        /* Try to find the filename */
        char *pszNameStart = rtManifestPosOfCharInBuf(pcBuf, cch, '(');
        if (!pszNameStart)
        {
            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
            break;
        }
        char *pszNameEnd = rtManifestPosOfCharInBuf(pcBuf, cch, ')');
        if (!pszNameEnd)
        {
            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
            break;
        }

        /* Copy the filename part */
        size_t cchName = pszNameEnd - pszNameStart - 1;
        char *pszName = (char *)RTMemTmpAlloc(cchName + 1);
        if (!pszName)
        {
            rc = VERR_NO_MEMORY;
            break;
        }
        memcpy(pszName, pszNameStart + 1, cchName);
        pszName[cchName] = '\0';

        /* Try to find the digest sum */
        char *pszDigestStart = rtManifestPosOfCharInBuf(pcBuf, cch, '=') + 1;
        if (!pszDigestStart)
        {
            RTMemTmpFree(pszName);
            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
            break;
        }
        char *pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\r');
        if (!pszDigestEnd)
            pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\n');
        if (!pszDigestEnd)
        {
            RTMemTmpFree(pszName);
            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
            break;
        }
        /* Copy the digest part */
        size_t cchDigest = pszDigestEnd - pszDigestStart - 1;
        char *pszDigest = (char *)RTMemTmpAlloc(cchDigest + 1);
        if (!pszDigest)
        {
            RTMemTmpFree(pszName);
            rc = VERR_NO_MEMORY;
            break;
        }
        memcpy(pszDigest, pszDigestStart + 1, cchDigest);
        pszDigest[cchDigest] = '\0';

        /* Check our file list against the extracted data */
        bool fFound = false;
        for (size_t i = 0; i < cTests; ++i)
        {
            /** @todo r=bird: Using RTStrStr here looks bogus. */
            if (RTStrStr(paFiles[i].pTestPattern->pszTestFile, RTStrStrip(pszName)) != NULL)
            {
                /* Add the data of the manifest file to the file list */
                paFiles[i].pszManifestFile = RTStrDup(RTStrStrip(pszName));
                paFiles[i].pszManifestDigest = RTStrDup(RTStrStrip(pszDigest));
                fFound = true;
                break;
            }
        }
        RTMemTmpFree(pszName);
        RTMemTmpFree(pszDigest);
        if (!fFound)
        {
            /* There have to be an entry in the file list */
            rc = VERR_MANIFEST_FILE_MISMATCH;
            break;
        }

        pcBuf += cch;
        cbRead += cch;
    }

    if (   rc == VINF_SUCCESS
        || rc == VERR_EOF)
    {
        rc = VINF_SUCCESS;
        for (size_t i = 0; i < cTests; ++i)
        {
            /* If there is an entry in the file list, which hasn't an
             * equivalent in the manifest file, its an error. */
            if (   !paFiles[i].pszManifestFile
                || !paFiles[i].pszManifestDigest)
            {
                rc = VERR_MANIFEST_FILE_MISMATCH;
                break;
            }

            /* Do the manifest SHA digest match against the actual digest? */
            if (RTStrICmp(paFiles[i].pszManifestDigest, paFiles[i].pTestPattern->pszTestDigest))
            {
                if (piFailed)
                    *piFailed = i;
                rc = VERR_MANIFEST_DIGEST_MISMATCH;
                break;
            }
        }
    }

    /* Cleanup */
    for (size_t i = 0; i < cTests; ++i)
    {
        if (paFiles[i].pszManifestFile)
            RTStrFree(paFiles[i].pszManifestFile);
        if (paFiles[i].pszManifestDigest)
            RTStrFree(paFiles[i].pszManifestDigest);
    }
    RTMemTmpFree(paFiles);

    RTPrintf("rc = %Rrc\n", rc);
    return rc;
}
static int scriptCommand(PVM pVM, const char *pszIn, size_t cch)
{
    NOREF(cch);
    int rc = VINF_SUCCESS;
    char *psz = RTStrDup(pszIn);
    char *pszEqual = strchr(psz, '=');
    if (pszEqual)
    {
        /*
         * var = value
         */
        *pszEqual = '\0';
        RTStrStripR(psz);
        char *pszValue = RTStrStrip(pszEqual + 1);

        /* variables */
        static struct
        {
            const char *pszVar;
            int (*pfnHandler)(PVM pVM, char *pszVar, char *pszValue, void *pvUser);
            PFNRT pvUser;
        } aVars[] =
        {
            { "eax", scriptGPReg,  (PFNRT)CPUMSetGuestEAX },
            { "ebx", scriptGPReg,  (PFNRT)CPUMSetGuestEBX },
            { "ecx", scriptGPReg,  (PFNRT)CPUMSetGuestECX },
            { "edx", scriptGPReg,  (PFNRT)CPUMSetGuestEDX },
            { "esp", scriptGPReg,  (PFNRT)CPUMSetGuestESP },
            { "ebp", scriptGPReg,  (PFNRT)CPUMSetGuestEBP },
            { "esi", scriptGPReg,  (PFNRT)CPUMSetGuestESI },
            { "edi", scriptGPReg,  (PFNRT)CPUMSetGuestEDI },
            { "efl", scriptGPReg,  (PFNRT)CPUMSetGuestEFlags },
            { "eip", scriptGPReg,  (PFNRT)CPUMSetGuestEIP },
            { "ss",  scriptSelReg, (PFNRT)CPUMSetGuestSS },
            { "cs",  scriptSelReg, (PFNRT)CPUMSetGuestCS },
            { "ds",  scriptSelReg, (PFNRT)CPUMSetGuestDS },
            { "es",  scriptSelReg, (PFNRT)CPUMSetGuestES },
            { "fs",  scriptSelReg, (PFNRT)CPUMSetGuestFS },
            { "gs",  scriptSelReg, (PFNRT)CPUMSetGuestGS },
            { "cr0", scriptSysReg, (PFNRT)CPUMSetGuestCR0 },
            { "cr2", scriptSysReg, (PFNRT)CPUMSetGuestCR2 },
            { "cr3", scriptSysReg, (PFNRT)CPUMSetGuestCR3 },
            { "cr4", scriptSysReg, (PFNRT)CPUMSetGuestCR4 },
            { "ldtr",scriptSelReg, (PFNRT)CPUMSetGuestLDTR },
            { "tr",  scriptSelReg, (PFNRT)CPUMSetGuestTR },
            { "idtr",scriptDtrReg, (PFNRT)CPUMSetGuestIDTR },
            { "gdtr",scriptDtrReg, (PFNRT)CPUMSetGuestGDTR }
        };

        rc = -1;
        for (unsigned i = 0; i < RT_ELEMENTS(aVars); i++)
        {
            if (!strcmp(psz, aVars[i].pszVar))
            {
                rc = aVars[i].pfnHandler(pVM, psz, pszValue, (void*)(uintptr_t)aVars[i].pvUser);
                break;
            }
        }
    }

    RTStrFree(psz);
    return rc;
}