/**
 * Writes a GSO frame to a stream.
 *
 * @returns IPRT status code, @see RTStrmWrite.
 *
 * @param   pStream         The stream handle.
 * @param   StartNanoTS     What to subtract from the RTTimeNanoTS output.
 * @param   pGso            Pointer to the GSO context.
 * @param   pvFrame         The start of the GSO frame.
 * @param   cbFrame         The size of the GSO frame.
 * @param   cbSegMax        The max number of bytes to include in the file for
 *                          each segment.
 */
int PcapStreamGsoFrame(PRTSTREAM pStream, uint64_t StartNanoTS, PCPDMNETWORKGSO pGso,
                       const void *pvFrame, size_t cbFrame, size_t cbSegMax)
{
    struct pcaprec_hdr Hdr;
    pcapCalcHeader(&Hdr, StartNanoTS, 0, 0);

    uint8_t const  *pbFrame = (uint8_t const *)pvFrame;
    uint8_t         abHdrs[256];
    uint32_t const  cSegs   = PDMNetGsoCalcSegmentCount(pGso, cbFrame);
    for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
    {
        uint32_t cbSegPayload;
        uint32_t offSegPayload = PDMNetGsoCarveSegment(pGso, pbFrame, cbFrame, iSeg, cSegs, abHdrs, &cbSegPayload);

        pcapUpdateHeader(&Hdr, pGso->cbHdrs + cbSegPayload, cbSegMax);
        int rc = RTStrmWrite(pStream, &Hdr, sizeof(Hdr));
        if (RT_FAILURE(rc))
            return rc;

        rc = RTStrmWrite(pStream, abHdrs, RT_MIN(Hdr.incl_len, pGso->cbHdrs));
        if (RT_SUCCESS(rc) && Hdr.incl_len > pGso->cbHdrs)
            rc = RTStrmWrite(pStream, pbFrame + offSegPayload, Hdr.incl_len - pGso->cbHdrs);
        if (RT_FAILURE(rc))
            return rc;
    }

    return VINF_SUCCESS;
}
/**
 * Writes a frame to a stream.
 *
 * @returns IPRT status code, @see RTStrmWrite.
 *
 * @param   pStream         The stream handle.
 * @param   StartNanoTS     What to subtract from the RTTimeNanoTS output.
 * @param   pvFrame         The start of the frame.
 * @param   cbFrame         The size of the frame.
 * @param   cbMax           The max number of bytes to include in the file.
 */
int PcapStreamFrame(PRTSTREAM pStream, uint64_t StartNanoTS, const void *pvFrame, size_t cbFrame, size_t cbMax)
{
    struct pcaprec_hdr Hdr;
    pcapCalcHeader(&Hdr, StartNanoTS, cbFrame, cbMax);
    int rc1 = RTStrmWrite(pStream, &Hdr, sizeof(Hdr));
    int rc2 = RTStrmWrite(pStream, pvFrame, Hdr.incl_len);
    return RT_SUCCESS(rc1) ? rc2 : rc1;
}
Exemple #3
0
/**
 * Prints a range of lines with a prefix.
 *
 * @param   pState              The diff state.
 * @param   chPrefix            The prefix.
 * @param   pStream             The stream to get the lines from.
 * @param   iLine               The first line.
 * @param   cLines              The number of lines.
 */
static void scmDiffPrintLines(PSCMDIFFSTATE pState, char chPrefix, PSCMSTREAM pStream, size_t iLine, size_t cLines)
{
    while (cLines-- > 0)
    {
        SCMEOL      enmEol;
        size_t      cchLine;
        const char *pchLine = ScmStreamGetLineByNo(pStream, iLine, &cchLine, &enmEol);

        RTStrmPutCh(pState->pDiff, chPrefix);
        if (pchLine && cchLine)
        {
            if (!pState->fSpecialChars)
                RTStrmWrite(pState->pDiff, pchLine, cchLine);
            else
            {
                size_t      offVir   = 0;
                const char *pchStart = pchLine;
                const char *pchTab   = (const char *)memchr(pchLine, '\t', cchLine);
                while (pchTab)
                {
                    RTStrmWrite(pState->pDiff, pchStart, pchTab - pchStart);
                    offVir += pchTab - pchStart;

                    size_t cchTab = pState->cchTab - offVir % pState->cchTab;
                    switch (cchTab)
                    {
                        case 1: RTStrmPutStr(pState->pDiff, "."); break;
                        case 2: RTStrmPutStr(pState->pDiff, ".."); break;
                        case 3: RTStrmPutStr(pState->pDiff, "[T]"); break;
                        case 4: RTStrmPutStr(pState->pDiff, "[TA]"); break;
                        case 5: RTStrmPutStr(pState->pDiff, "[TAB]"); break;
                        default: RTStrmPrintf(pState->pDiff, "[TAB%.*s]", cchTab - 5, g_szTabSpaces); break;
                    }
                    offVir += cchTab;

                    /* next */
                    pchStart = pchTab + 1;
                    pchTab = (const char *)memchr(pchStart, '\t', cchLine - (pchStart - pchLine));
                }
                size_t cchLeft = cchLine - (pchStart - pchLine);
                if (cchLeft)
                    RTStrmWrite(pState->pDiff, pchStart, cchLeft);
            }
        }

        if (!pState->fSpecialChars)
            RTStrmPutCh(pState->pDiff, '\n');
        else if (enmEol == SCMEOL_LF)
            RTStrmPutStr(pState->pDiff, "[LF]\n");
        else if (enmEol == SCMEOL_CRLF)
            RTStrmPutStr(pState->pDiff, "[CRLF]\n");
        else
            RTStrmPutStr(pState->pDiff, "[NONE]\n");

        iLine++;
    }
}
/** Write a character to standard output and print an error and return false on
 * failure. */
bool outputCharacter(char ch)
{
    int rc = RTStrmWrite(g_pStdOut, &ch, 1);
    if (RT_FAILURE(rc))
    {
        RTStrmPrintf(g_pStdErr, "Error writing output: %Rrc\n", rc);
        return false;
    }
    return true;
}
Exemple #5
0
int main(int argc, char **argv)
{
    int rc = RTR3InitExe(argc, &argv, 0);
    if (RT_FAILURE(rc))
        return RTMsgInitFailure(rc);

    /*
     * Create an empty address space that we can load modules and stuff into
     * as we parse the parameters.
     */
    RTDBGAS hDbgAs;
    rc = RTDbgAsCreate(&hDbgAs, 0, RTUINTPTR_MAX, "");
    if (RT_FAILURE(rc))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDBgAsCreate -> %Rrc", rc);

    /*
     * Create a debugging configuration instance to work with so that we can
     * make use of (i.e. test) path searching and such.
     */
    RTDBGCFG hDbgCfg;
    rc = RTDbgCfgCreate(&hDbgCfg, "IPRT", true /*fNativePaths*/);
    if (RT_FAILURE(rc))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgCfgCreate -> %Rrc", rc);

    /*
     * Parse arguments.
     */
    static const RTGETOPTDEF s_aOptions[] =
    {
        { "--input",        'i', RTGETOPT_REQ_STRING },
        { "--local-file",   'l', RTGETOPT_REQ_NOTHING },
        { "--cache-file",   'c', RTGETOPT_REQ_NOTHING },
        { "--pe-image",     'p', RTGETOPT_REQ_NOTHING },
        { "--verbose",      'v', RTGETOPT_REQ_NOTHING },
        { "--x86",          '8', RTGETOPT_REQ_NOTHING },
        { "--amd64",        '6', RTGETOPT_REQ_NOTHING },
        { "--whatever",     '*', RTGETOPT_REQ_NOTHING },
    };

    PRTSTREAM       pInput          = g_pStdIn;
    PRTSTREAM       pOutput         = g_pStdOut;
    unsigned        cVerbosityLevel = 0;
    enum {
        kOpenMethod_FromImage,
        kOpenMethod_FromPeImage
    }               enmOpenMethod   = kOpenMethod_FromImage;
    bool            fCacheFile      = false;
    RTLDRARCH       enmArch         = RTLDRARCH_WHATEVER;

    RTGETOPTUNION   ValueUnion;
    RTGETOPTSTATE   GetState;
    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
    while ((rc = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (rc)
        {
            case 'i':
                rc = RTStrmOpen(ValueUnion.psz, "r", &pInput);
                if (RT_FAILURE(rc))
                    return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open '%s' for reading: %Rrc", ValueUnion.psz, rc);
                break;

            case 'c':
                fCacheFile = true;
                break;

            case 'l':
                fCacheFile = false;
                break;

            case 'p':
                enmOpenMethod = kOpenMethod_FromPeImage;
                break;

            case 'v':
                cVerbosityLevel++;
                break;

            case '8':
                enmArch = RTLDRARCH_X86_32;
                break;

            case '6':
                enmArch = RTLDRARCH_AMD64;
                break;

            case '*':
                enmArch = RTLDRARCH_WHATEVER;
                break;

            case 'h':
                RTPrintf("Usage: %s [options] <module> <address> [<module> <address> [..]]\n"
                         "\n"
                         "Options:\n"
                         "  -i,--input=file\n"
                         "      Specify a input file instead of standard input.\n"
                         "  --pe-image\n"
                         "      Use RTDbgModCreateFromPeImage to open the file."
                         "  -v, --verbose\n"
                         "      Display the address space before doing the filtering.\n"
                         "  --amd64,--x86,--whatever\n"
                         "      Selects the desired architecture.\n"
                         "  -h, -?, --help\n"
                         "      Display this help text and exit successfully.\n"
                         "  -V, --version\n"
                         "      Display the revision and exit successfully.\n"
                         , RTPathFilename(argv[0]));
                return RTEXITCODE_SUCCESS;

            case 'V':
                RTPrintf("$Revision$\n");
                return RTEXITCODE_SUCCESS;

            case VINF_GETOPT_NOT_OPTION:
            {
                /* <module> <address> */
                const char *pszModule = ValueUnion.psz;

                rc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX);
                if (RT_FAILURE(rc))
                    return RTGetOptPrintError(rc, &ValueUnion);
                uint64_t u64Address = ValueUnion.u64;

                uint32_t cbImage    = 0;
                uint32_t uTimestamp = 0;
                if (fCacheFile)
                {
                    rc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX);
                    if (RT_FAILURE(rc))
                        return RTGetOptPrintError(rc, &ValueUnion);
                    cbImage = ValueUnion.u32;

                    rc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX);
                    if (RT_FAILURE(rc))
                        return RTGetOptPrintError(rc, &ValueUnion);
                    uTimestamp = ValueUnion.u32;
                }

                RTDBGMOD hMod;
                if (enmOpenMethod == kOpenMethod_FromImage)
                    rc = RTDbgModCreateFromImage(&hMod, pszModule, NULL, enmArch, hDbgCfg);
                else
                    rc = RTDbgModCreateFromPeImage(&hMod, pszModule, NULL, NIL_RTLDRMOD, cbImage, uTimestamp, hDbgCfg);
                if (RT_FAILURE(rc))
                    return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgModCreateFromImage(,%s,,) -> %Rrc", pszModule, rc);

                rc = RTDbgAsModuleLink(hDbgAs, hMod, u64Address, 0 /* fFlags */);
                if (RT_FAILURE(rc))
                    return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgAsModuleLink(,%s,%llx,) -> %Rrc", pszModule, u64Address, rc);
                break;
            }

            default:
                return RTGetOptPrintError(rc, &ValueUnion);
        }
    }

    /*
     * Display the address space.
     */
    if (cVerbosityLevel)
    {
        RTPrintf("*** Address Space Dump ***\n");
        uint32_t cModules = RTDbgAsModuleCount(hDbgAs);
        for (uint32_t iModule = 0; iModule < cModules; iModule++)
        {
            RTDBGMOD        hDbgMod = RTDbgAsModuleByIndex(hDbgAs, iModule);
            RTPrintf("Module #%u: %s\n", iModule, RTDbgModName(hDbgMod));

            RTDBGASMAPINFO  aMappings[128];
            uint32_t        cMappings = RT_ELEMENTS(aMappings);
            rc = RTDbgAsModuleQueryMapByIndex(hDbgAs, iModule, &aMappings[0], &cMappings, 0 /*fFlags*/);
            if (RT_SUCCESS(rc))
            {
                for (uint32_t iMapping = 0; iMapping < cMappings; iMapping++)
                {
                    if (aMappings[iMapping].iSeg == NIL_RTDBGSEGIDX)
                        RTPrintf("  mapping #%u: %RTptr-%RTptr\n",
                                 iMapping,
                                 aMappings[iMapping].Address,
                                 aMappings[iMapping].Address + RTDbgModImageSize(hDbgMod) - 1);
                    else
                    {
                        RTDBGSEGMENT SegInfo;
                        rc = RTDbgModSegmentByIndex(hDbgMod, aMappings[iMapping].iSeg, &SegInfo);
                        if (RT_SUCCESS(rc))
                            RTPrintf("  mapping #%u: %RTptr-%RTptr (segment #%u - '%s')",
                                     iMapping,
                                     aMappings[iMapping].Address,
                                     aMappings[iMapping].Address + SegInfo.cb,
                                     SegInfo.iSeg, SegInfo.szName);
                        else
                            RTPrintf("  mapping #%u: %RTptr-???????? (segment #%u)", iMapping, aMappings[iMapping].Address);
                    }

                    if (cVerbosityLevel > 1)
                    {
                        uint32_t cSymbols = RTDbgModSymbolCount(hDbgMod);
                        RTPrintf("    %u symbols\n", cSymbols);
                        for (uint32_t iSymbol = 0; iSymbol < cSymbols; iSymbol++)
                        {
                            RTDBGSYMBOL SymInfo;
                            rc = RTDbgModSymbolByOrdinal(hDbgMod, iSymbol, &SymInfo);
                            if (RT_SUCCESS(rc))
                                RTPrintf("    #%04u at %08x:%RTptr %05llx %s\n",
                                         SymInfo.iOrdinal, SymInfo.iSeg, SymInfo.offSeg,
                                         (uint64_t)SymInfo.cb, SymInfo.szName);
                        }
                    }
                }
            }
            else
                RTMsgError("RTDbgAsModuleQueryMapByIndex failed: %Rrc", rc);
            RTDbgModRelease(hDbgMod);
        }
        RTPrintf("*** End of Address Space Dump ***\n");
    }

    /*
     * Read text from standard input and see if there is anything we can translate.
     */
    for (;;)
    {
        /* Get a line. */
        char szLine[_64K];
        rc = RTStrmGetLine(pInput, szLine, sizeof(szLine));
        if (rc == VERR_EOF)
            break;
        if (RT_FAILURE(rc))
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTStrmGetLine() -> %Rrc\n", rc);

        /*
         * Search the line for potential addresses and replace them with
         * symbols+offset.
         */
        const char *pszStart = szLine;
        const char *psz      = szLine;
        char        ch;
        while ((ch = *psz) != '\0')
        {
            size_t      cchAddress;
            uint64_t    u64Address;

            if (   (   ch == '0'
                    && (psz[1] == 'x' || psz[1] == 'X')
                    && TryParseAddress(psz, &cchAddress, &u64Address))
                || (   RT_C_IS_XDIGIT(ch)
                    && TryParseAddress(psz, &cchAddress, &u64Address))
               )
            {
                /* Print. */
                psz += cchAddress;
                if (pszStart != psz)
                    RTStrmWrite(pOutput, pszStart, psz - pszStart);
                pszStart = psz;

                /* Try get the module. */
                RTUINTPTR   uAddr;
                RTDBGSEGIDX iSeg;
                RTDBGMOD    hDbgMod;
                rc = RTDbgAsModuleByAddr(hDbgAs, u64Address, &hDbgMod, &uAddr, &iSeg);
                if (RT_SUCCESS(rc))
                {
                    if (iSeg != UINT32_MAX)
                        RTStrmPrintf(pOutput, "=[%s:%u", RTDbgModName(hDbgMod), iSeg);
                    else
                        RTStrmPrintf(pOutput, "=[%s", RTDbgModName(hDbgMod), iSeg);

                    /*
                     * Do we have symbols?
                     */
                    RTDBGSYMBOL Symbol;
                    RTINTPTR    offSym;
                    rc = RTDbgAsSymbolByAddr(hDbgAs, u64Address, RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL, &offSym, &Symbol, NULL);
                    if (RT_SUCCESS(rc))
                    {
                        if (!offSym)
                            RTStrmPrintf(pOutput, "!%s", Symbol.szName);
                        else if (offSym > 0)
                            RTStrmPrintf(pOutput, "!%s+%#llx", Symbol.szName, offSym);
                        else
                            RTStrmPrintf(pOutput, "!%s-%#llx", Symbol.szName, -offSym);
                    }
                    else
                        RTStrmPrintf(pOutput, "+%#llx", u64Address - uAddr);

                    /*
                     * Do we have line numbers?
                     */
                    RTDBGLINE   Line;
                    RTINTPTR    offLine;
                    rc = RTDbgAsLineByAddr(hDbgAs, u64Address, &offLine, &Line, NULL);
                    if (RT_SUCCESS(rc))
                        RTStrmPrintf(pOutput, " %Rbn(%u)", Line.szFilename, Line.uLineNo);

                    RTStrmPrintf(pOutput, "]");
                    RTDbgModRelease(hDbgMod);
                }
            }
            else
                psz++;
        }

        if (pszStart != psz)
            RTStrmWrite(pOutput, pszStart, psz - pszStart);
        RTStrmPutCh(pOutput, '\n');

    }

    return RTEXITCODE_SUCCESS;
}
/**
 * Writes the stream header.
 *
 * @returns IPRT status code, @see RTStrmWrite.
 *
 * @param   pStream         The stream handle.
 * @param   StartNanoTS     What to subtract from the RTTimeNanoTS output.
 */
int PcapStreamHdr(PRTSTREAM pStream, uint64_t StartNanoTS)
{
    int rc1 = RTStrmWrite(pStream, &s_Hdr, sizeof(s_Hdr));
    int rc2 = PcapStreamFrame(pStream, StartNanoTS, s_szDummyData, 60, sizeof(s_szDummyData));
    return RT_SUCCESS(rc1) ? rc2 : rc1;
}
int main(int argc, char **argv)
{
    unsigned cErrors = 0;

    RTR3InitExe(argc, &argv, 0);

    if (argc <= 1)
    {
        RTPrintf("usage: %s default\n", argv[0]);
        return 1;
    }

    for (int i = 1; i < argc; i++)
    {
        if (!strcmp(argv[i], "default"))
            ;
        else
        {
            RTPrintf("Unknown parameter '%s'\n", argv[i]);
            return 1;
        }
    }

    RTHTTP hHttp;
    char *pszBuf = NULL;
    PRTSTREAM CAFile = NULL;

    int rc = RTHttpCreate(&hHttp);

    // create certificate file
    if (RT_SUCCESS(rc))
        rc = RTStrmOpen(CAFILE_NAME, "w+b", &CAFile);

    // fetch root CA certificate (new one, often avoided in cert chains by
    // using an intermediate cert which is signed by old root)
    if (RT_SUCCESS(rc))
        rc = RTHttpGet(hHttp,
                       "http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem",
                       &pszBuf);
    if (RT_SUCCESS(rc) && pszBuf)
    {
        uint8_t *abSha1;
        size_t  cbSha1;
        uint8_t *abSha512;
        size_t  cbSha512;
        size_t cbBuf = strlen(pszBuf);
        const uint8_t abSha1PCA3G5[] =
        {
            0x4e, 0xb6, 0xd5, 0x78, 0x49, 0x9b, 0x1c, 0xcf, 0x5f, 0x58,
            0x1e, 0xad, 0x56, 0xbe, 0x3d, 0x9b, 0x67, 0x44, 0xa5, 0xe5
        };
        const uint8_t abSha512PCA3G5[] =
        {
            0xd4, 0xf8, 0x10, 0x54, 0x72, 0x77, 0x0a, 0x2d,
            0xe3, 0x17, 0xb3, 0xcf, 0xed, 0x61, 0xae, 0x5c,
            0x5d, 0x3e, 0xde, 0xa1, 0x41, 0x35, 0xb2, 0xdf,
            0x60, 0xe2, 0x61, 0xfe, 0x3a, 0xc1, 0x66, 0xa3,
            0x3c, 0x88, 0x54, 0x04, 0x4f, 0x1d, 0x13, 0x46,
            0xe3, 0x8c, 0x06, 0x92, 0x9d, 0x70, 0x54, 0xc3,
            0x44, 0xeb, 0x2c, 0x74, 0x25, 0x9e, 0x5d, 0xfb,
            0xd2, 0x6b, 0xa8, 0x9a, 0xf0, 0xb3, 0x6a, 0x01
        };
        rc = RTHttpCertDigest(hHttp, pszBuf, cbBuf,
                              &abSha1, &cbSha1, &abSha512, &cbSha512);
        if (RT_SUCCESS(rc))
        {
            if (cbSha1 != sizeof(abSha1PCA3G5))
            {
                RTPrintf("Wrong SHA1 digest size of PCA-3G5\n");
                rc = VERR_INTERNAL_ERROR;
            }
            else if (memcmp(abSha1PCA3G5, abSha1, cbSha1))
            {
                RTPrintf("Wrong SHA1 digest for PCA-3G5:\n"
                        "Got:      %.*Rhxs\n"
                        "Expected: %.*Rhxs\n",
                        cbSha1, abSha1, sizeof(abSha1PCA3G5), abSha1PCA3G5);
                rc = VERR_INTERNAL_ERROR;
            }
            if (cbSha512 != sizeof(abSha512PCA3G5))
            {
                RTPrintf("Wrong SHA512 digest size of PCA-3G5\n");
                rc = VERR_INTERNAL_ERROR;
            }
            else if (memcmp(abSha512PCA3G5, abSha512, cbSha512))
            {
                RTPrintf("Wrong SHA512 digest for PCA-3G5:\n"
                        "Got:      %.*Rhxs\n"
                        "Expected: %.*Rhxs\n",
                        cbSha512, abSha512, sizeof(abSha512PCA3G5), abSha512PCA3G5);
                rc = VERR_INTERNAL_ERROR;
            }
            RTMemFree(abSha1);
            RTMemFree(abSha512);
            if (RT_SUCCESS(rc))
                rc = RTStrmWrite(CAFile, pszBuf, cbBuf);
            if (RT_SUCCESS(rc))
                rc = RTStrmWrite(CAFile, RTFILE_LINEFEED, strlen(RTFILE_LINEFEED));
        }
    }
    if (pszBuf)
    {
        RTMemFree(pszBuf);
        pszBuf = NULL;
    }

    // fetch root CA certificate (old one, but still very widely used)
    if (RT_SUCCESS(rc))
        rc = RTHttpGet(hHttp,
                       "http://www.verisign.com/repository/roots/root-certificates/PCA-3.pem",
                       &pszBuf);
    if (RT_SUCCESS(rc) && pszBuf)
    {
        uint8_t *abSha1;
        size_t  cbSha1;
        uint8_t *abSha512;
        size_t  cbSha512;
        size_t  cbBuf = strlen(pszBuf);
        const uint8_t abSha1PCA3[] =
        {
            0xa1, 0xdb, 0x63, 0x93, 0x91, 0x6f, 0x17, 0xe4, 0x18, 0x55,
            0x09, 0x40, 0x04, 0x15, 0xc7, 0x02, 0x40, 0xb0, 0xae, 0x6b
        };
        const uint8_t abSha512PCA3[] =
        {
            0xbb, 0xf7, 0x8a, 0x19, 0x9f, 0x37, 0xee, 0xa2,
            0xce, 0xc8, 0xaf, 0xe3, 0xd6, 0x22, 0x54, 0x20,
            0x74, 0x67, 0x6e, 0xa5, 0x19, 0xb7, 0x62, 0x1e,
            0xc1, 0x2f, 0xd5, 0x08, 0xf4, 0x64, 0xc4, 0xc6,
            0xbb, 0xc2, 0xf2, 0x35, 0xe7, 0xbe, 0x32, 0x0b,
            0xde, 0xb2, 0xfc, 0x44, 0x92, 0x5b, 0x8b, 0x9b,
            0x77, 0xa5, 0x40, 0x22, 0x18, 0x12, 0xcb, 0x3d,
            0x0a, 0x67, 0x83, 0x87, 0xc5, 0x45, 0xc4, 0x99
        };
        rc = RTHttpCertDigest(hHttp, pszBuf, cbBuf,
                              &abSha1, &cbSha1, &abSha512, &cbSha512);
        if (RT_SUCCESS(rc))
        {
            if (cbSha1 != sizeof(abSha1PCA3))
            {
                RTPrintf("Wrong SHA1 digest size of PCA-3\n");
                rc = VERR_INTERNAL_ERROR;
            }
            else if (memcmp(abSha1PCA3, abSha1, cbSha1))
            {
                RTPrintf("Wrong SHA1 digest for PCA-3:\n"
                        "Got:      %.*Rhxs\n"
                        "Expected: %.*Rhxs\n",
                        cbSha1, abSha1, sizeof(abSha1PCA3), abSha1PCA3);
                rc = VERR_INTERNAL_ERROR;
            }
            if (cbSha512 != sizeof(abSha512PCA3))
            {
                RTPrintf("Wrong SHA512 digest size of PCA-3\n");
                rc = VERR_INTERNAL_ERROR;
            }
            else if (memcmp(abSha512PCA3, abSha512, cbSha512))
            {
                RTPrintf("Wrong SHA512 digest for PCA-3:\n"
                        "Got:      %.*Rhxs\n"
                        "Expected: %.*Rhxs\n",
                        cbSha512, abSha512, sizeof(abSha512PCA3), abSha512PCA3);
                rc = VERR_INTERNAL_ERROR;
            }
            RTMemFree(abSha1);
            RTMemFree(abSha512);
            if (RT_SUCCESS(rc))
                rc = RTStrmWrite(CAFile, pszBuf, cbBuf);
            if (RT_SUCCESS(rc))
                rc = RTStrmWrite(CAFile, RTFILE_LINEFEED, strlen(RTFILE_LINEFEED));
        }
    }
    if (pszBuf)
    {
        RTMemFree(pszBuf);
        pszBuf = NULL;
    }

    // close certificate file
    if (CAFile)
    {
        RTStrmClose(CAFile);
        CAFile = NULL;
    }

    if (RT_SUCCESS(rc))
        rc = RTHttpSetCAFile(hHttp, CAFILE_NAME);

    if (RT_SUCCESS(rc))
        rc = RTHttpGet(hHttp,
                       "https://update.virtualbox.org/query.php?platform=LINUX_32BITS_UBUNTU_12_04&version=4.1.18",
                       &pszBuf);

    if (   RT_FAILURE(rc)
        && rc != VERR_HTTP_COULDNT_CONNECT)
        cErrors++;

    if (RT_FAILURE(rc))
        RTPrintf("Error code: %Rrc\n", rc);
    else
        RTPrintf("Success!\n");
    RTPrintf("Got: %s\n", pszBuf);
    if (pszBuf)
    {
        RTMemFree(pszBuf);
        pszBuf = NULL;
    }

    RTHttpDestroy(hHttp);

//    RTFileDelete(CAFILE_NAME);

    return !!cErrors;
}
static int extractPCA3G5(RTHTTP hHttp, PRTSTREAM CAFile, uint8_t *pu8Buf, size_t cbBuf)
{
    uint8_t *abSha1;
    size_t  cbSha1;
    uint8_t *abSha512;
    size_t  cbSha512;
    char *pszBuf = (char*)pu8Buf;

    const uint8_t abSha1PCA3G5[] =
    {
        0x4e, 0xb6, 0xd5, 0x78, 0x49, 0x9b, 0x1c, 0xcf, 0x5f, 0x58,
        0x1e, 0xad, 0x56, 0xbe, 0x3d, 0x9b, 0x67, 0x44, 0xa5, 0xe5
    };
    const uint8_t abSha512PCA3G5[] =
    {
        0xd4, 0xf8, 0x10, 0x54, 0x72, 0x77, 0x0a, 0x2d,
        0xe3, 0x17, 0xb3, 0xcf, 0xed, 0x61, 0xae, 0x5c,
        0x5d, 0x3e, 0xde, 0xa1, 0x41, 0x35, 0xb2, 0xdf,
        0x60, 0xe2, 0x61, 0xfe, 0x3a, 0xc1, 0x66, 0xa3,
        0x3c, 0x88, 0x54, 0x04, 0x4f, 0x1d, 0x13, 0x46,
        0xe3, 0x8c, 0x06, 0x92, 0x9d, 0x70, 0x54, 0xc3,
        0x44, 0xeb, 0x2c, 0x74, 0x25, 0x9e, 0x5d, 0xfb,
        0xd2, 0x6b, 0xa8, 0x9a, 0xf0, 0xb3, 0x6a, 0x01
    };
    int rc = RTHttpCertDigest(hHttp, pszBuf, cbBuf,
                              &abSha1, &cbSha1, &abSha512, &cbSha512);
    if (RT_SUCCESS(rc))
    {
        if (cbSha1 != sizeof(abSha1PCA3G5))
        {
            RTPrintf("Wrong SHA1 digest size of PCA-3G5\n");
            rc = VERR_INTERNAL_ERROR;
        }
        else if (memcmp(abSha1PCA3G5, abSha1, cbSha1))
        {
            RTPrintf("Wrong SHA1 digest for PCA-3G5:\n"
                     "Got:      %.*Rhxs\n"
                     "Expected: %.*Rhxs\n",
                     cbSha1, abSha1, sizeof(abSha1PCA3G5), abSha1PCA3G5);
            rc = VERR_INTERNAL_ERROR;
        }
        if (cbSha512 != sizeof(abSha512PCA3G5))
        {
            RTPrintf("Wrong SHA512 digest size of PCA-3G5\n");
            rc = VERR_INTERNAL_ERROR;
        }
        else if (memcmp(abSha512PCA3G5, abSha512, cbSha512))
        {
            RTPrintf("Wrong SHA512 digest for PCA-3G5:\n"
                     "Got:      %.*Rhxs\n"
                     "Expected: %.*Rhxs\n",
                     cbSha512, abSha512, sizeof(abSha512PCA3G5), abSha512PCA3G5);
            rc = VERR_INTERNAL_ERROR;
        }
        RTMemFree(abSha1);
        RTMemFree(abSha512);
        if (RT_SUCCESS(rc))
            rc = RTStrmWrite(CAFile, pszBuf, cbBuf);
        if (RT_SUCCESS(rc))
            rc = RTStrmWrite(CAFile, RTFILE_LINEFEED, strlen(RTFILE_LINEFEED));
    }
    return rc;
}
static int extractPCA3(RTHTTP hHttp, PRTSTREAM CAFile, uint8_t *pu8Buf, size_t cbBuf)
{
    uint8_t *abSha1;
    size_t  cbSha1;
    uint8_t *abSha512;
    size_t  cbSha512;
    char *pszBuf = (char*)pu8Buf;

    const uint8_t abSha1PCA3[] =
    {
        0xa1, 0xdb, 0x63, 0x93, 0x91, 0x6f, 0x17, 0xe4, 0x18, 0x55,
        0x09, 0x40, 0x04, 0x15, 0xc7, 0x02, 0x40, 0xb0, 0xae, 0x6b
    };
    const uint8_t abSha512PCA3[] =
    {
        0xbb, 0xf7, 0x8a, 0x19, 0x9f, 0x37, 0xee, 0xa2,
        0xce, 0xc8, 0xaf, 0xe3, 0xd6, 0x22, 0x54, 0x20,
        0x74, 0x67, 0x6e, 0xa5, 0x19, 0xb7, 0x62, 0x1e,
        0xc1, 0x2f, 0xd5, 0x08, 0xf4, 0x64, 0xc4, 0xc6,
        0xbb, 0xc2, 0xf2, 0x35, 0xe7, 0xbe, 0x32, 0x0b,
        0xde, 0xb2, 0xfc, 0x44, 0x92, 0x5b, 0x8b, 0x9b,
        0x77, 0xa5, 0x40, 0x22, 0x18, 0x12, 0xcb, 0x3d,
        0x0a, 0x67, 0x83, 0x87, 0xc5, 0x45, 0xc4, 0x99
    };
    int rc = RTHttpCertDigest(hHttp, pszBuf, cbBuf,
                              &abSha1, &cbSha1, &abSha512, &cbSha512);
    if (RT_SUCCESS(rc))
    {
        if (cbSha1 != sizeof(abSha1PCA3))
        {
            RTPrintf("Wrong SHA1 digest size of PCA-3\n");
            rc = VERR_INTERNAL_ERROR;
        }
        else if (memcmp(abSha1PCA3, abSha1, cbSha1))
        {
            RTPrintf("Wrong SHA1 digest for PCA-3:\n"
                     "Got:      %.*Rhxs\n"
                     "Expected: %.*Rhxs\n",
                     cbSha1, abSha1, sizeof(abSha1PCA3), abSha1PCA3);
            rc = VERR_INTERNAL_ERROR;
        }
        if (cbSha512 != sizeof(abSha512PCA3))
        {
            RTPrintf("Wrong SHA512 digest size of PCA-3\n");
            rc = VERR_INTERNAL_ERROR;
        }
        else if (memcmp(abSha512PCA3, abSha512, cbSha512))
        {
            RTPrintf("Wrong SHA512 digest for PCA-3:\n"
                     "Got:      %.*Rhxs\n"
                     "Expected: %.*Rhxs\n",
                     cbSha512, abSha512, sizeof(abSha512PCA3), abSha512PCA3);
            rc = VERR_INTERNAL_ERROR;
        }
        RTMemFree(abSha1);
        RTMemFree(abSha512);
        if (RT_SUCCESS(rc))
            rc = RTStrmWrite(CAFile, pszBuf, cbBuf);
        if (RT_SUCCESS(rc))
            rc = RTStrmWrite(CAFile, RTFILE_LINEFEED, strlen(RTFILE_LINEFEED));
    }

    return rc;
}
RTDECL(int) RTCrStoreCertExportAsPem(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename)
{
    /*
     * Validate input.
     */
    AssertReturn(!fFlags, VERR_INVALID_FLAGS);

    /*
     * Start the enumeration first as this validates the store handle.
     */
    RTCRSTORECERTSEARCH Search;
    int rc = RTCrStoreCertFindAll(hStore, &Search);
    if (RT_SUCCESS(rc))
    {
        /*
         * Open the file for writing.
         *
         * Note! We must use text and no binary here, because the base-64 API
         *       below will use host specific EOL markers, not CRLF as PEM
         *       specifies.
         */
        PRTSTREAM hStrm;
        rc = RTStrmOpen(pszFilename, "w", &hStrm);
        if (RT_SUCCESS(rc))
        {
            /*
             * Enumerate the certificates in the store, writing them out one by one.
             */
            size_t          cbBase64  = 0;
            char           *pszBase64 = NULL;
            PCRTCRCERTCTX   pCertCtx;
            while ((pCertCtx = RTCrStoreCertSearchNext(hStore, &Search)) != NULL)
            {
                const char *pszMarker;
                switch (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK)
                {
                    case RTCRCERTCTX_F_ENC_X509_DER:    pszMarker = "CERTIFICATE";  break;
                    case RTCRCERTCTX_F_ENC_TAF_DER:     pszMarker = "TRUST ANCHOR"; break;
                    default:                            pszMarker = NULL;           break;
                }
                if (pszMarker && pCertCtx->cbEncoded > 0)
                {
                    /*
                     * Do the base64 conversion first.
                     */
                    size_t cchEncoded = RTBase64EncodedLength(pCertCtx->cbEncoded);
                    if (cchEncoded < cbBase64)
                    { /* likely */ }
                    else
                    {
                        size_t cbNew = RT_ALIGN(cchEncoded + 64, 128);
                        void *pvNew = RTMemRealloc(pszBase64, cbNew);
                        if (!pvNew)
                        {
                            rc = VERR_NO_MEMORY;
                            break;
                        }
                        cbBase64  = cbNew;
                        pszBase64 = (char *)pvNew;
                    }
                    rc = RTBase64Encode(pCertCtx->pabEncoded, pCertCtx->cbEncoded, pszBase64, cbBase64, &cchEncoded);
                    if (RT_FAILURE(rc))
                        break;

                    RTStrmPrintf(hStrm, "-----BEGIN %s-----\n", pszMarker);
                    RTStrmWrite(hStrm, pszBase64, cchEncoded);
                    rc = RTStrmPrintf(hStrm, "\n-----END %s-----\n", pszMarker);
                    if (RT_FAILURE(rc))
                        break;
                }

                RTCrCertCtxRelease(pCertCtx);
            }
            if (pCertCtx)
                RTCrCertCtxRelease(pCertCtx);
            RTMemFree(pszBase64);

            /*
             * Flush the output file before closing.
             */
            int rc2 = RTStrmFlush(hStrm);
            if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
                rc = rc2;
            RTStrmClearError(hStrm); /** @todo fix RTStrmClose... */
            rc2 = RTStrmClose(hStrm);
            if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
                rc = rc2;
        }

        int rc2 = RTCrStoreCertSearchDestroy(hStore, &Search); AssertRC(rc2);
    }
    return rc;
}
RTDECL(RTEXITCODE) RTPathRmCmd(unsigned cArgs, char **papszArgs)
{
    /*
     * Parse the command line.
     */
    static const RTGETOPTDEF s_aOptions[] =
    {
        /* operations */
        { "--dirs-and-more",        'd', RTGETOPT_REQ_NOTHING },
        { "--force",                'f', RTGETOPT_REQ_NOTHING },
        { "--prompt",               'i', RTGETOPT_REQ_NOTHING },
        { "--prompt-once",          'I', RTGETOPT_REQ_NOTHING },
        { "--interactive",      RTPATHRMCMD_OPT_INTERACTIVE, RTGETOPT_REQ_STRING },
        { "--one-file-system",  RTPATHRMCMD_OPT_ONE_FILE_SYSTEM, RTGETOPT_REQ_NOTHING },
        { "--preserve-root",    RTPATHRMCMD_OPT_PRESERVE_ROOT, RTGETOPT_REQ_NOTHING },
        { "--no-preserve-root", RTPATHRMCMD_OPT_NO_PRESERVE_ROOT, RTGETOPT_REQ_NOTHING },
        { "--recursive",            'R', RTGETOPT_REQ_NOTHING },
        { "--recursive",            'r', RTGETOPT_REQ_NOTHING },
        { "--safe-delete",          'P', RTGETOPT_REQ_NOTHING },
        { "--verbose",              'v', RTGETOPT_REQ_NOTHING },

        /* IPRT extensions */
        { "--machine-readable", RTPATHRMCMD_OPT_MACHINE_READABLE, RTGETOPT_REQ_NOTHING },
        { "--machinereadable",  RTPATHRMCMD_OPT_MACHINE_READABLE, RTGETOPT_REQ_NOTHING }, /* bad long option style */
    };

    RTGETOPTSTATE GetState;
    int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
                          RTGETOPTINIT_FLAGS_OPTS_FIRST);
    if (RT_FAILURE(rc))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOpt failed: %Rrc", rc);

    RTPATHRMCMDOPTS Opts;
    RT_ZERO(Opts);
    Opts.fPreserveRoot  = true;
    Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_NONE;

    RTGETOPTUNION   ValueUnion;
    while (   (rc = RTGetOpt(&GetState, &ValueUnion)) != 0
           && rc != VINF_GETOPT_NOT_OPTION)
    {
        switch (rc)
        {
            case 'd':
                Opts.fDirsAndOther = true;
                break;

            case 'f':
                Opts.fForce = true;
                Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_NONE;
                break;

            case 'i':
                Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ALL;
                break;

            case 'I':
                Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ONCE;
                break;

            case RTPATHRMCMD_OPT_INTERACTIVE:
                if (!strcmp(ValueUnion.psz, "always"))
                    Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ALL;
                else if (!strcmp(ValueUnion.psz, "once"))
                    Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ONCE;
                else
                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown --interactive option value: '%s'\n", ValueUnion.psz);
                break;

            case RTPATHRMCMD_OPT_ONE_FILE_SYSTEM:
                Opts.fOneFileSystem = true;
                break;

            case RTPATHRMCMD_OPT_PRESERVE_ROOT:
                Opts.fPreserveRoot = true;
                break;

            case RTPATHRMCMD_OPT_NO_PRESERVE_ROOT:
                Opts.fPreserveRoot = false;
                break;

            case 'R':
            case 'r':
                Opts.fRecursive = true;
                Opts.fDirsAndOther = true;
                break;

            case 'P':
                Opts.fSafeDelete = true;
                break;

            case 'v':
                Opts.fVerbose = true;
                break;


            case RTPATHRMCMD_OPT_MACHINE_READABLE:
                Opts.fMachineReadable = true;
                break;

            case 'h':
                RTPrintf("Usage: to be written\nOption dump:\n");
                for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
                    if (RT_C_IS_PRINT(s_aOptions[i].iShort))
                        RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
                    else
                        RTPrintf(" %s\n", s_aOptions[i].pszLong);
                return RTEXITCODE_SUCCESS;

            case 'V':
                RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
                return RTEXITCODE_SUCCESS;

            default:
                return RTGetOptPrintError(rc, &ValueUnion);
        }
    }

    /*
     * Options we don't support.
     */
    if (Opts.fOneFileSystem)
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "The --one-file-system option is not yet implemented.\n");
    if (Opts.enmInteractive != RTPATHRMCMDINTERACTIVE_NONE)
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "The -i, -I and --interactive options are not implemented yet.\n");

    /*
     * No files means error.
     */
    if (rc != VINF_GETOPT_NOT_OPTION && !Opts.fForce)
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "No files or directories specified.\n");

    /*
     * Machine readable init + header.
     */
    if (Opts.fMachineReadable)
    {
        rc = RTStrmSetMode(g_pStdOut, true /*fBinary*/, false /*fCurrentCodeSet*/);
        if (RT_FAILURE(rc))
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTStrmSetMode failed: %Rrc.\n", rc);
        static const char s_achHeader[] = "hdr_id=rm\0hdr_ver=1";
        RTStrmWrite(g_pStdOut, s_achHeader, sizeof(s_achHeader));
    }

    /*
     * Delete the specified files/dirs/whatever.
     */
    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
    while (rc == VINF_GETOPT_NOT_OPTION)
    {
        rc = rtPathRmOne(&Opts, ValueUnion.psz);
        if (RT_FAILURE(rc))
            rcExit = RTEXITCODE_FAILURE;

        /* next */
        rc = RTGetOpt(&GetState, &ValueUnion);
    }
    if (rc != 0)
        rcExit = RTGetOptPrintError(rc, &ValueUnion);

    /*
     * Terminate the machine readable stuff.
     */
    if (Opts.fMachineReadable)
    {
        RTStrmWrite(g_pStdOut, "\0\0\0", 4);
        rc = RTStrmFlush(g_pStdOut);
        if (RT_FAILURE(rc) && rcExit == RTEXITCODE_SUCCESS)
            rcExit = RTEXITCODE_FAILURE;
    }

    return rcExit;
}
/** The actual implemenation code for @a createServiceFile. */
bool createServiceFileCore(char **ppachTemplate,
                           struct SERVICEPARAMETERS *pParameters)
{
    /* The size of the template data we have read. */
    size_t cchTemplate = 0;
    /* The size of the buffer we have allocated. */
    size_t cbBuffer = 0;
    /* How much of the template data we have written out. */
    size_t cchWritten = 0;
    int rc = VINF_SUCCESS;
    /* First of all read in the file. */
    while (rc != VINF_EOF)
    {
        size_t cchRead;

        if (cchTemplate == cbBuffer)
        {
            cbBuffer += READ_SIZE;
            *ppachTemplate = (char *)RTMemRealloc((void *)*ppachTemplate,
                                                  cbBuffer);
        }
        if (!*ppachTemplate)
        {
            RTStrmPrintf(g_pStdErr, "Out of memory.\n");
            return false;
        }
        rc = RTStrmReadEx(g_pStdIn, *ppachTemplate + cchTemplate,
                          cbBuffer - cchTemplate, &cchRead);
        if (RT_FAILURE(rc))
        {
            RTStrmPrintf(g_pStdErr, "Error reading input: %Rrc\n", rc);
            return false;
        }
        if (!cchRead)
            rc = VINF_EOF;
        cchTemplate += cchRead;
    }
    while (true)
    {
        /* Find the next '%' character if any and write out up to there (or the
         * end if there is no '%'). */
        char *pchNext = (char *) memchr((void *)(*ppachTemplate + cchWritten),
                                        '%', cchTemplate - cchWritten);
        size_t cchToWrite =   pchNext
                            ? pchNext - *ppachTemplate - cchWritten
                            : cchTemplate - cchWritten;
        rc = RTStrmWrite(g_pStdOut, *ppachTemplate + cchWritten, cchToWrite);
        if (RT_FAILURE(rc))
        {
            RTStrmPrintf(g_pStdErr, "Error writing output: %Rrc\n", rc);
            return false;
        }
        cchWritten += cchToWrite;
        if (!pchNext)
            break;
        /* And substitute any of our well-known strings.  We favour code
         * readability over efficiency here. */
        if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                        COMMAND, sizeof(COMMAND) - 1))
        {
            if (!pParameters->pcszCommand)
            {
                RTStrmPrintf(g_pStdErr, "--command not specified.\n");
                return false;
            }
            if (!writeCommand(pParameters->enmFormat,
                              pParameters->pcszCommand))
                return false;
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             ARGUMENTS, sizeof(ARGUMENTS) - 1))
        {
            if (   pParameters->pcszArguments
                && !writeQuoted(pParameters->enmFormat,
                                pParameters->pcszArguments))
                return false;
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             DESCRIPTION, sizeof(DESCRIPTION) - 1))
        {
            if (!pParameters->pcszDescription)
            {
                RTStrmPrintf(g_pStdErr, "--description not specified.\n");
                return false;
            }
            if (!writePrintableString(pParameters->enmFormat,
                                      pParameters->pcszDescription))
                return false;
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             SERVICE_NAME, sizeof(SERVICE_NAME) - 1))
        {
            if (   !pParameters->pcszCommand
                && !pParameters->pcszServiceName)
            {
                RTStrmPrintf(g_pStdErr, "Neither --command nor --service-name specified.\n");
                return false;
            }
            if (pParameters->pcszServiceName)
            {
                if (!writePrintableString(pParameters->enmFormat,
                                          pParameters->pcszServiceName))
                    return false;
            }
            else
            {
                const char *pcszFileName = RTPathFilename(pParameters->pcszCommand);
                const char *pcszSuffix   = RTPathSuffix(pParameters->pcszCommand);
                char *pszName = RTStrDupN(pcszFileName,
                                            pcszSuffix
                                          ? pcszSuffix - pcszFileName
                                          : RTPATH_MAX);
                bool fRc;
                if (!pszName)
                {
                    RTStrmPrintf(g_pStdErr, "Out of memory.\n");
                    return false;
                }
                fRc = writePrintableString(pParameters->enmFormat,
                                           pszName);
                RTStrFree(pszName);
                if (!fRc)
                    return false;
            }
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             HAVE_ONESHOT, sizeof(HAVE_ONESHOT) - 1))
        {
            if (!pParameters->fOneShot)
                skipLine(*ppachTemplate, cchTemplate, &cchWritten);
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             HAVE_DAEMON, sizeof(HAVE_DAEMON) - 1))
        {
            if (pParameters->fOneShot)
                skipLine(*ppachTemplate, cchTemplate, &cchWritten);
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             STOP_COMMAND, sizeof(STOP_COMMAND) - 1))
        {
            if (   pParameters->pcszStopCommand
                && !writeCommand(pParameters->enmFormat,
                                 pParameters->pcszStopCommand))
                return false;
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             STOP_ARGUMENTS, sizeof(STOP_ARGUMENTS) - 1))
        {
            if (   pParameters->pcszStopArguments
                && !writeQuoted(pParameters->enmFormat,
                                pParameters->pcszStopArguments))
                return false;
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             HAVE_STOP_COMMAND, sizeof(HAVE_STOP_COMMAND) - 1))
        {
            if (!pParameters->pcszStopCommand)
                skipLine(*ppachTemplate, cchTemplate, &cchWritten);
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             NO_STOP_COMMAND, sizeof(NO_STOP_COMMAND) - 1))
        {
            if (pParameters->pcszStopCommand)
                skipLine(*ppachTemplate, cchTemplate, &cchWritten);
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             STATUS_COMMAND, sizeof(STATUS_COMMAND) - 1))
        {
            if (   pParameters->pcszStatusCommand
                && !writeCommand(pParameters->enmFormat,
                                 pParameters->pcszStatusCommand))
                return false;
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             STATUS_ARGUMENTS, sizeof(STATUS_ARGUMENTS) - 1))
        {
            if (   pParameters->pcszStatusArguments
                && !writeQuoted(pParameters->enmFormat,
                                pParameters->pcszStatusArguments))
                return false;
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             HAVE_STATUS_COMMAND,
                             sizeof(HAVE_STATUS_COMMAND) - 1))
        {
            if (!pParameters->pcszStatusCommand)
                skipLine(*ppachTemplate, cchTemplate, &cchWritten);
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             NO_STATUS_COMMAND, sizeof(NO_STATUS_COMMAND) - 1))
        {
            if (pParameters->pcszStatusCommand)
                skipLine(*ppachTemplate, cchTemplate, &cchWritten);
        }
        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
                             "%%", 2))
        {
            rc = RTStrmPutCh(g_pStdOut, '%');
            if (RT_FAILURE(rc))
            {
                RTStrmPrintf(g_pStdErr, "Error writing output: %Rrc\n", rc);
                return false;
            }
        }
        else
        {
            RTStrmPrintf(g_pStdErr, "Unknown substitution sequence in input at \"%.*s\"\n",
                         RT_MIN(16, cchTemplate - cchWritten),
                         *ppachTemplate + cchWritten);
            return false;
        }
   }
    return true;
}