Exemple #1
0
/**
 * Search for a USB test device and return the device path.
 *
 * @returns Path to the USB test device or NULL if none was found.
 */
static char *usbTestFindDevice(void)
{
    /*
     * Very crude and quick way to search for the correct test device.
     * Assumption is that the path looks like /dev/bus/usb/%3d/%3d.
     */
    uint8_t uBus = 1;
    bool fBusExists = false;
    char aszDevPath[64];

    RT_ZERO(aszDevPath);

    do
    {
        RTStrPrintf(aszDevPath, sizeof(aszDevPath), "/dev/bus/usb/%03d", uBus);

        fBusExists = RTPathExists(aszDevPath);

        if (fBusExists)
        {
            /* Check every device. */
            bool fDevExists = false;
            uint8_t uDev = 1;

            do
            {
                RTStrPrintf(aszDevPath, sizeof(aszDevPath), "/dev/bus/usb/%03d/%03d", uBus, uDev);

                fDevExists = RTPathExists(aszDevPath);

                if (fDevExists)
                {
                    RTFILE hFileDev;
                    int rc = RTFileOpen(&hFileDev, aszDevPath, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
                    if (RT_SUCCESS(rc))
                    {
                        USBDEVDESC DevDesc;

                        rc = RTFileRead(hFileDev, &DevDesc, sizeof(DevDesc), NULL);
                        RTFileClose(hFileDev);

                        if (   RT_SUCCESS(rc)
                            && DevDesc.idVendor == 0x0525
                            && DevDesc.idProduct == 0xa4a0)
                            return RTStrDup(aszDevPath);
                    }
                }

                uDev++;
            } while (fDevExists);
        }

        uBus++;
    } while (fBusExists);

    return NULL;
}
static int NetIfAdpCtl(const char * pcszIfName, const char *pszAddr, const char *pszOption, const char *pszMask)
{
    const char *args[] = { NULL, pcszIfName, pszAddr, pszOption, pszMask, NULL };

    char szAdpCtl[RTPATH_MAX];
    int rc = RTPathExecDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME));
    if (RT_FAILURE(rc))
    {
        LogRel(("NetIfAdpCtl: failed to get program path, rc=%Rrc.\n", rc));
        return rc;
    }
    strcat(szAdpCtl, "/" VBOXNETADPCTL_NAME);
    args[0] = szAdpCtl;
    if (!RTPathExists(szAdpCtl))
    {
        LogRel(("NetIfAdpCtl: path %s does not exist. Failed to run " VBOXNETADPCTL_NAME " helper.\n",
                szAdpCtl));
        return VERR_FILE_NOT_FOUND;
    }

    RTPROCESS pid;
    rc = RTProcCreate(szAdpCtl, args, RTENV_DEFAULT, 0, &pid);
    if (RT_SUCCESS(rc))
    {
        RTPROCSTATUS Status;
        rc = RTProcWait(pid, 0, &Status);
        if (   RT_SUCCESS(rc)
            && Status.iStatus == 0
            && Status.enmReason == RTPROCEXITREASON_NORMAL)
            return VINF_SUCCESS;
    }
    else
        LogRel(("NetIfAdpCtl: failed to create process for %s: %Rrc\n", szAdpCtl, rc));
    return rc;
}
STDMETHODIMP SharedFolder::COMGETTER(Accessible) (BOOL *aAccessible)
{
    CheckComArgOutPointerValid(aAccessible);

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    /* mName and mHostPath are constant during life time, no need to lock */

    /* check whether the host path exists */
    Utf8Str hostPath = m->strHostPath;
    char hostPathFull[RTPATH_MAX];
    int vrc = RTPathExists(hostPath.c_str()) ? RTPathReal(hostPath.c_str(),
                                                          hostPathFull,
                                                          sizeof(hostPathFull))
                                      : VERR_PATH_NOT_FOUND;
    if (RT_SUCCESS(vrc))
    {
        *aAccessible = TRUE;
        return S_OK;
    }

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    m->strLastAccessError = Utf8StrFmt(tr("'%s' is not accessible (%Rrc)"),
                                       m->strHostPath.c_str(),
                                       vrc);

    LogWarningThisFunc(("m.lastAccessError=\"%s\"\n", m->strLastAccessError.c_str()));

    *aAccessible = FALSE;
    return S_OK;
}
/* static */
int getDriveInfoFromSysfs(DriveInfoList *pList, bool isDVD, bool *pfSuccess)
{
    AssertPtrReturn(pList, VERR_INVALID_POINTER);
    AssertPtrNullReturn(pfSuccess, VERR_INVALID_POINTER); /* Valid or Null */
    LogFlowFunc (("pList=%p, isDVD=%u, pfSuccess=%p\n",
                  pList, (unsigned) isDVD, pfSuccess));
    RTDIR hDir;
    int rc;
    bool fSuccess = false;
    unsigned cFound = 0;

    if (!RTPathExists("/sys"))
        return VINF_SUCCESS;
    rc = RTDirOpen(&hDir, "/sys/block");
    /* This might mean that sysfs semantics have changed */
    AssertReturn(rc != VERR_FILE_NOT_FOUND, VINF_SUCCESS);
    fSuccess = true;
    if (RT_SUCCESS(rc))
    {
        for (;;)
        {
            RTDIRENTRY entry;
            rc = RTDirRead(hDir, &entry, NULL);
            Assert(rc != VERR_BUFFER_OVERFLOW);  /* Should never happen... */
            if (RT_FAILURE(rc))  /* Including overflow and no more files */
                break;
            if (entry.szName[0] == '.')
                continue;
            sysfsBlockDev dev(entry.szName, isDVD);
            /* This might mean that sysfs semantics have changed */
            AssertBreakStmt(dev.isConsistent(), fSuccess = false);
            if (!dev.isValid())
                continue;
            try
            {
                pList->push_back(DriveInfo(dev.getNode(), dev.getUdi(), dev.getDesc()));
            }
            catch(std::bad_alloc &e)
            {
                rc = VERR_NO_MEMORY;
                break;
            }
            ++cFound;
        }
        RTDirClose(hDir);
    }
    if (rc == VERR_NO_MORE_FILES)
        rc = VINF_SUCCESS;
    if (RT_FAILURE(rc))
        /* Clean up again */
        for (unsigned i = 0; i < cFound; ++i)
            pList->pop_back();
    if (pfSuccess)
        *pfSuccess = fSuccess;
    LogFlow (("rc=%Rrc, fSuccess=%u\n", rc, (unsigned) fSuccess));
    return rc;
}
Exemple #5
0
/**
 * Loads a dynamic load library (/shared object) image file residing in the
 * RTPathAppPrivateArch() directory.
 *
 * Suffix is not required.
 *
 * @returns iprt status code.
 * @param   pszFilename Image filename. No path.
 * @param   phLdrMod    Where to store the handle to the loaded module.
 */
RTDECL(int) RTLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod)
{
    LogFlow(("RTLdrLoadAppPriv: pszFilename=%p:{%s} phLdrMod=%p\n", pszFilename, pszFilename, phLdrMod));

    /*
     * Validate input.
     */
    AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
    *phLdrMod = NIL_RTLDRMOD;
    AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
    AssertMsgReturn(!RTPathHasPath(pszFilename), ("%s\n", pszFilename), VERR_INVALID_PARAMETER);

    /*
     * Check the filename.
     */
    size_t cchFilename = strlen(pszFilename);
    AssertMsgReturn(cchFilename < (RTPATH_MAX / 4) * 3, ("%zu\n", cchFilename), VERR_INVALID_PARAMETER);

    const char *pszSuffix = "";
    size_t cchSuffix = 0;
    if (!RTPathHasSuffix(pszFilename))
    {
        pszSuffix = RTLdrGetSuff();
        cchSuffix = strlen(pszSuffix);
    }

    /*
     * Construct the private arch path and check if the file exists.
     */
    char szPath[RTPATH_MAX];
    int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - 1 - cchSuffix - cchFilename);
    AssertRCReturn(rc, rc);

    char *psz = strchr(szPath, '\0');
    *psz++ = RTPATH_SLASH;
    memcpy(psz, pszFilename, cchFilename);
    psz += cchFilename;
    memcpy(psz, pszSuffix, cchSuffix + 1);

    if (!RTPathExists(szPath))
    {
        LogRel(("RTLdrLoadAppPriv: \"%s\" not found\n", szPath));
        return VERR_FILE_NOT_FOUND;
    }

    /*
     * Pass it on to RTLdrLoad.
     */
    rc = RTLdrLoad(szPath, phLdrMod);

    LogFlow(("RTLdrLoadAppPriv: returns %Rrc\n", rc));
    return rc;
}
Exemple #6
0
/**
 * Adds a file to the cache.
 *
 * @returns IPRT status code.
 * @param   pszSrcPath      Path to the source file.
 * @param   pszDstName      The name of the destionation file (no path stuff).
 * @param   pszExtraSuff    Optional extra suffix. Mach-O dSYM hack.
 * @param   pszDstSubDir    The subdirectory to file it under.  This is the
 *                          stringification of a relatively unique identifier of
 *                          the file in question.
 * @param   pAddToUuidMap   Optional file UUID that is used to create a UUID map
 *                          entry.
 * @param   pszUuidMapDir   The UUID map subdirectory in the cache, if this is
 *                          wanted, otherwise NULL.
 * @param   pCfg            The configuration.
 */
static int rtDbgSymCacheAddOneFile(const char *pszSrcPath, const char *pszDstName, const char *pszExtraStuff,
                                   const char *pszDstSubDir, PRTUUID pAddToUuidMap, const char *pszUuidMapDir,
                                   PCRTDBGSYMCACHEADDCFG pCfg)
{
    /*
     * Build and create the destination path, step by step.
     */
    char szDstPath[RTPATH_MAX];
    int rc = RTPathJoin(szDstPath, sizeof(szDstPath), pCfg->pszCache, pszDstName);
    if (RT_FAILURE(rc))
        return RTMsgErrorRc(rc, "Error constructing cache path for '%s': %Rrc", pszSrcPath, rc);

    if (!RTDirExists(szDstPath))
    {
        rc = RTDirCreate(szDstPath, 0755, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL);
        if (RT_FAILURE(rc))
            return RTMsgErrorRc(rc, "Error creating '%s': %Rrc", szDstPath, rc);
    }

    rc = RTPathAppend(szDstPath, sizeof(szDstPath), pszDstSubDir);
    if (RT_FAILURE(rc))
        return RTMsgErrorRc(rc, "Error constructing cache path for '%s': %Rrc", pszSrcPath, rc);

    if (!RTDirExists(szDstPath))
    {
        rc = RTDirCreate(szDstPath, 0755, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL);
        if (RT_FAILURE(rc))
            return RTMsgErrorRc(rc, "Error creating '%s': %Rrc", szDstPath, rc);
    }

    rc = RTPathAppend(szDstPath, sizeof(szDstPath), pszDstName);
    if (RT_FAILURE(rc))
        return RTMsgErrorRc(rc, "Error constructing cache path for '%s': %Rrc", pszSrcPath, rc);
    if (pszExtraStuff)
    {
        rc = RTStrCat(szDstPath, sizeof(szDstPath), pszExtraStuff);
        if (RT_FAILURE(rc))
            return RTMsgErrorRc(rc, "Error constructing cache path for '%s': %Rrc", pszSrcPath, rc);
    }

    /*
     * If the file exists, we compare the two and throws an error if the doesn't match.
     */
    if (RTPathExists(szDstPath))
    {
        rc = RTFileCompare(pszSrcPath, szDstPath);
        if (RT_SUCCESS(rc))
        {
            RTMsgInfo("%s is already in the cache.", pszSrcPath);
            if (pAddToUuidMap && pszUuidMapDir)
                return rtDbgSymCacheAddCreateUuidMapping(szDstPath, pAddToUuidMap, pszUuidMapDir, pCfg);
            return VINF_SUCCESS;
        }
        if (rc == VERR_NOT_EQUAL)
            RTMsgInfo("Cache conflict with existing entry '%s' when inserting '%s'.", szDstPath, pszSrcPath);
        else
            RTMsgInfo("Error comparing '%s' with '%s': %Rrc", pszSrcPath, szDstPath, rc);
        if (!pCfg->fOverwriteOnConflict)
            return rc;
    }

    /*
     * The file doesn't exist or we should overwrite it,
     */
    RTMsgInfo("Copying '%s' to '%s'...", pszSrcPath, szDstPath);
    rc = RTFileCopy(pszSrcPath, szDstPath);
    if (RT_FAILURE(rc))
        return RTMsgErrorRc(rc, "Error copying '%s' to '%s': %Rrc", pszSrcPath, szDstPath, rc);
    if (pAddToUuidMap && pszUuidMapDir)
        return rtDbgSymCacheAddCreateUuidMapping(szDstPath, pAddToUuidMap, pszUuidMapDir, pCfg);
    return VINF_SUCCESS;
}
Exemple #7
0
/**
 * Handles the 'add' command.
 *
 * @returns Program exit code.
 * @param   pszArg0             The program name.
 * @param   cArgs               The number of arguments to the 'add' command.
 * @param   papszArgs           The argument vector, starting after 'add'.
 */
static RTEXITCODE rtDbgSymCacheCmdAdd(const char *pszArg0, int cArgs, char **papszArgs)
{
    /*
     * Parse the command line.
     */
    static RTGETOPTDEF const s_aOptions[] =
    {
        { "--recursive",                'R', RTGETOPT_REQ_NOTHING },
        { "--no-recursive",             'n', RTGETOPT_REQ_NOTHING },
        { "--overwrite-on-conflict",    'o', RTGETOPT_REQ_NOTHING },
    };

    const char *pszCache                = NULL;
    bool        fRecursive              = false;
    bool        fOverwriteOnConflict    = false;

    RTGETOPTSTATE State;
    int rc = RTGetOptInit(&State, cArgs, papszArgs, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 0,  RTGETOPTINIT_FLAGS_OPTS_FIRST);
    if (RT_FAILURE(rc))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc", rc);

    uint32_t        cAdded = 0;
    RTGETOPTUNION   ValueUnion;
    int             chOpt;
    while ((chOpt = RTGetOpt(&State, &ValueUnion)) != 0)
    {
        switch (chOpt)
        {
            case 'R':
                fRecursive = true;
                break;

            case 'n':
                fRecursive = false;
                break;

            case 'o':
                fOverwriteOnConflict = true;
                break;

            case VINF_GETOPT_NOT_OPTION:
                /* The first non-option is a cache directory. */
                if (!pszCache)
                {
                    pszCache = ValueUnion.psz;
                    if (!RTPathExists(pszCache))
                    {
                        rc = RTDirCreate(pszCache, 0755, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL);
                        if (RT_FAILURE(rc))
                            return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Error creating cache directory '%s': %Rrc", pszCache, rc);
                    }
                    else if (!RTDirExists(pszCache))
                        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Specified cache directory is not a directory: '%s'", pszCache);
                }
                /* Subsequent non-options are files to be added to the cache. */
                else
                {
                    RTEXITCODE rcExit = rtDbgSymCacheAddFileOrDir(ValueUnion.psz, pszCache, fRecursive, fOverwriteOnConflict);
                    if (rcExit != RTEXITCODE_FAILURE)
                        return rcExit;
                }
                break;

            case 'h':
                return rtDbgSymCacheUsage(pszArg0, "add");
            case 'V':
                return rtDbgSymCacheVersion();
            default:
                return RTGetOptPrintError(chOpt, &ValueUnion);
        }
    }

    if (!pszCache)
        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No cache directory or files to add were specified.");
    return RTEXITCODE_SUCCESS;
}
/**
 * Worker that we can wrap with error variable saving and restoring.
 */
static bool rtAssertShouldPanicWorker(void)
{
    /*
     * Check for the VBOX_ASSERT variable.
     */
    const char *psz = RTEnvGet("VBOX_ASSERT");

    /* not defined => default behaviour. */
    if (!psz)
        return true;

    /* 'breakpoint' or 'panic' means default behaviour. */
    if (!strcmp(psz, "breakpoint") || !strcmp(psz, "panic"))
        return true;

#ifdef VBOX_RTASSERT_WITH_GDB
    /* 'gdb' - means try launch a gdb session in xterm. */
    if (!strcmp(psz, "gdb"))
    {
        /* Did we already fire up gdb? If so, just hit the breakpoint. */
        static bool volatile s_fAlreadyLaunchedGdb = false;
        if (ASMAtomicUoReadBool(&s_fAlreadyLaunchedGdb))
            return true;

        /* Try find a suitable terminal program. */
        const char *pszTerm = RTEnvGet("VBOX_ASSERT_TERM");
        if (    !pszTerm
            ||  !RTPathExists(pszTerm))
        {
            pszTerm = "/usr/bin/gnome-terminal";
            if (!RTPathExists(pszTerm))
            {
                pszTerm = "/usr/X11R6/bin/xterm";
                if (!RTPathExists(pszTerm))
                {
                    pszTerm ="/usr/bin/xterm";
                    if (!RTPathExists(pszTerm))
                        return true;
                }
            }
        }

        /* And find gdb. */
        const char *pszGdb = RTEnvGet("VBOX_ASSERT_GDB");
        if (    !pszGdb
            ||  !RTPathExists(pszGdb))
        {
            pszGdb = "/usr/bin/gdb";
            if (!RTPathExists(pszGdb))
                pszGdb = "gdb";
        }

        /* Try spawn the process. */
        char    szCmd[512];
        size_t  cch = RTStrPrintf(szCmd, sizeof(szCmd), "%s -p %d ", pszGdb, RTProcSelf());
        if (cch < sizeof(szCmd))
        {
            char *pszExecName = &szCmd[cch];
            if (!RTProcGetExecutablePath(pszExecName, sizeof(szCmd) - cch))
                *pszExecName = '\0';
        }
        const char *apszArgs[] =
        {
            pszTerm,
            "-e",
            szCmd,
            NULL
        };
        RTPROCESS Process;
        int rc = RTProcCreate(apszArgs[0], &apszArgs[0], RTENV_DEFAULT, 0, &Process);
        if (RT_FAILURE(rc))
            return false;

        ASMAtomicWriteBool(&s_fAlreadyLaunchedGdb, true);

        /* Wait for gdb to attach. */
        RTThreadSleep(15000);
        return true;
    }
#endif

    /* '*' - don't hit the breakpoint. */
    return false;
}
int main(int argc, char **argv)
{
    RTEXITCODE rcExit = RTTestInitAndCreate("tstRTPrfIO", &g_hTest);
    if (rcExit != RTEXITCODE_SUCCESS)
        return rcExit;
    RTTestBanner(g_hTest);

    /*
     * Parse arguments
     */
    static const RTGETOPTDEF s_aOptions[] =
    {
        { "--test-dir",     'd',    RTGETOPT_REQ_STRING },
    };
    bool fFileOpenCloseTest = true;
    bool fFileWriteByteTest = true;
    bool fPathQueryInfoTest = true;
    //bool fFileTests = true;
    //bool fDirTests  = true;

    int ch;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (ch)
        {
            case 'd':
                g_pszTestDir = ValueUnion.psz;
                break;

            case 'V':
                RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "$Revision$\n");
                return RTTestSummaryAndDestroy(g_hTest);

            case 'h':
                RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "usage: testname [-d <testdir>]\n");
                return RTTestSummaryAndDestroy(g_hTest);

            default:
                RTTestFailed(g_hTest, "invalid argument");
                RTGetOptPrintError(ch, &ValueUnion);
                return RTTestSummaryAndDestroy(g_hTest);
        }
    }

    /*
     * Set up and check the prerequisites.
     */
    RTTESTI_CHECK_RC(RTPathJoin(g_szTestFile1,      sizeof(g_szTestFile1),      g_pszTestDir, "tstRTPrfIO-TestFile1"), VINF_SUCCESS);
    RTTESTI_CHECK_RC(RTPathJoin(g_szTestDir1,       sizeof(g_szTestDir1),       g_pszTestDir, "tstRTPrfIO-TestDir1"), VINF_SUCCESS);
    RTTESTI_CHECK_RC(RTPathJoin(g_szNotExitingFile, sizeof(g_szNotExitingFile), g_pszTestDir, "tstRTPrfIO-nonexistent-file"), VINF_SUCCESS);
    RTTESTI_CHECK_RC(RTPathJoin(g_szNotExitingDir,  sizeof(g_szNotExitingDir),  g_pszTestDir, "tstRTPrfIO-nonexistent-dir"), VINF_SUCCESS);
    RTTESTI_CHECK_RC(RTPathJoin(g_szNotExitingDirFile, sizeof(g_szNotExitingDirFile),  g_szNotExitingDir, "nonexistent-file"), VINF_SUCCESS);
    RTTESTI_CHECK(RTDirExists(g_pszTestDir));
    if (RTPathExists(g_szTestDir1))
        RTTestFailed(g_hTest, "The primary test directory (%s) already exist, please remove it", g_szTestDir1);
    if (RTPathExists(g_szTestFile1))
        RTTestFailed(g_hTest, "The primary test file (%s) already exist, please remove it", g_szTestFile1);
    if (RTPathExists(g_szNotExitingFile))
        RTTestFailed(g_hTest, "'%s' exists, remove it", g_szNotExitingFile);
    if (RTPathExists(g_szNotExitingDir))
        RTTestFailed(g_hTest, "'%s' exists, remove it", g_szNotExitingDir);
    if (RTPathExists(g_szNotExitingDirFile))
        RTTestFailed(g_hTest, "'%s' exists, remove it", g_szNotExitingDirFile);

    /*
     * Do the testing.
     */
    if (RTTestIErrorCount() == 0)
    {
#if 1
        if (fPathQueryInfoTest)
            benchmarkPathQueryInfo();
        if (fFileOpenCloseTest)
            benchmarkFileOpenClose();
#endif
        if (fFileWriteByteTest)
            benchmarkFileWriteByte();
        //if (fFileTests)
        //    benchmarkFile();
        //if (fDirTests)
        //    benchmarkDir();

        /*
         * Cleanup.
         */
        RTFileDelete(g_szTestFile1);
        RTDirRemoveRecursive(g_szTestDir1, 0);
        RTTESTI_CHECK(RTDirExists(g_pszTestDir));
        RTTESTI_CHECK(!RTPathExists(g_szTestDir1));
        RTTESTI_CHECK(!RTPathExists(g_szTestFile1));
    }

    return RTTestSummaryAndDestroy(g_hTest);
}
static RTEXITCODE HandleExtractExeSignerCert(int cArgs, char **papszArgs)
{
    /*
     * Parse arguments.
     */
    static const RTGETOPTDEF s_aOptions[] =
    {
        { "--ber",    'b', RTGETOPT_REQ_NOTHING },
        { "--cer",    'c', RTGETOPT_REQ_NOTHING },
        { "--der",    'd', RTGETOPT_REQ_NOTHING },
        { "--exe",    'e', RTGETOPT_REQ_STRING },
        { "--output", 'o', RTGETOPT_REQ_STRING },
    };

    const char *pszExe = NULL;
    const char *pszOut = NULL;
    RTLDRARCH   enmLdrArch   = RTLDRARCH_WHATEVER;
    uint32_t    fCursorFlags = RTASN1CURSOR_FLAGS_DER;

    RTGETOPTSTATE GetState;
    int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
    AssertRCReturn(rc, RTEXITCODE_FAILURE);
    RTGETOPTUNION ValueUnion;
    int ch;
    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (ch)
        {
            case 'e':   pszExe = ValueUnion.psz; break;
            case 'o':   pszOut = ValueUnion.psz; break;
            case 'b':   fCursorFlags = 0; break;
            case 'c':   fCursorFlags = RTASN1CURSOR_FLAGS_CER; break;
            case 'd':   fCursorFlags = RTASN1CURSOR_FLAGS_DER; break;
            case 'V':   return HandleVersion(cArgs, papszArgs);
            case 'h':   return HelpExtractExeSignerCert(g_pStdOut, RTSIGNTOOLHELP_FULL);

            case VINF_GETOPT_NOT_OPTION:
                if (!pszExe)
                    pszExe = ValueUnion.psz;
                else if (!pszOut)
                    pszOut = ValueUnion.psz;
                else
                    return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many file arguments: %s", ValueUnion.psz);
                break;

            default:
                return RTGetOptPrintError(ch, &ValueUnion);
        }
    }
    if (!pszExe)
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given.");
    if (!pszOut)
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "No output file given.");
    if (RTPathExists(pszOut))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "The output file '%s' exists.", pszOut);

    /*
     * Do it.
     */

    /* Open the executable image and query the PKCS7 info. */
    RTLDRMOD hLdrMod;
    rc = RTLdrOpen(pszExe, RTLDR_O_FOR_VALIDATION, enmLdrArch, &hLdrMod);
    if (RT_FAILURE(rc))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening executable image '%s': %Rrc", pszExe, rc);

    RTEXITCODE rcExit = RTEXITCODE_FAILURE;
#ifdef DEBUG
    size_t     cbBuf = 64;
#else
    size_t     cbBuf = _512K;
#endif
    void      *pvBuf = RTMemAlloc(cbBuf);
    size_t     cbRet = 0;
    rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbRet);
    if (rc == VERR_BUFFER_OVERFLOW && cbRet < _4M && cbRet > 0)
    {
        RTMemFree(pvBuf);
        cbBuf = cbRet;
        pvBuf = RTMemAlloc(cbBuf);
        rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbRet);
    }
    if (RT_SUCCESS(rc))
    {
        static RTERRINFOSTATIC s_StaticErrInfo;
        RTErrInfoInitStatic(&s_StaticErrInfo);

        /*
         * Decode the output.
         */
        RTASN1CURSORPRIMARY PrimaryCursor;
        RTAsn1CursorInitPrimary(&PrimaryCursor, pvBuf, (uint32_t)cbRet, &s_StaticErrInfo.Core,
                                &g_RTAsn1DefaultAllocator, fCursorFlags, "exe");
        RTCRPKCS7CONTENTINFO Pkcs7Ci;
        rc = RTCrPkcs7ContentInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &Pkcs7Ci, "pkcs7");
        if (RT_SUCCESS(rc))
        {
            if (RTCrPkcs7ContentInfo_IsSignedData(&Pkcs7Ci))
            {
                PCRTCRPKCS7SIGNEDDATA pSd = Pkcs7Ci.u.pSignedData;
                if (pSd->SignerInfos.cItems == 1)
                {
                    PCRTCRPKCS7ISSUERANDSERIALNUMBER pISN = &pSd->SignerInfos.paItems[0].IssuerAndSerialNumber;
                    PCRTCRX509CERTIFICATE pCert;
                    pCert = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(&pSd->Certificates,
                                                                                &pISN->Name, &pISN->SerialNumber);
                    if (pCert)
                    {
                        /*
                         * Write it out.
                         */
                        RTFILE hFile;
                        rc = RTFileOpen(&hFile, pszOut, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE);
                        if (RT_SUCCESS(rc))
                        {
                            uint32_t cbCert = pCert->SeqCore.Asn1Core.cbHdr + pCert->SeqCore.Asn1Core.cb;
                            rc = RTFileWrite(hFile, pCert->SeqCore.Asn1Core.uData.pu8 - pCert->SeqCore.Asn1Core.cbHdr,
                                             cbCert, NULL);
                            if (RT_SUCCESS(rc))
                            {
                                rc = RTFileClose(hFile);
                                if (RT_SUCCESS(rc))
                                {
                                    hFile  = NIL_RTFILE;
                                    rcExit = RTEXITCODE_SUCCESS;
                                    RTMsgInfo("Successfully wrote %u bytes to '%s'", cbCert, pszOut);
                                }
                                else
                                    RTMsgError("RTFileClose failed: %Rrc", rc);
                            }
                            else
                                RTMsgError("RTFileWrite failed: %Rrc", rc);
                            RTFileClose(hFile);
                        }
                        else
                            RTMsgError("Error opening '%s': %Rrc", pszOut, rc);
                    }
                    else
                        RTMsgError("Certificate not found.");
                }
                else
                    RTMsgError("SignerInfo count: %u", pSd->SignerInfos.cItems);
            }
            else
                RTMsgError("No PKCS7 content: ContentType=%s", Pkcs7Ci.ContentType.szObjId);
            RTAsn1VtDelete(&Pkcs7Ci.SeqCore.Asn1Core);
        }
        else
            RTMsgError("RTPkcs7ContentInfoDecodeAsn1 failed: %Rrc - %s", rc, s_StaticErrInfo.szMsg);
    }
    else
        RTMsgError("RTLDRPROP_PKCS7_SIGNED_DATA failed on '%s': %Rrc", pszExe, rc);
    RTMemFree(pvBuf);
    rc = RTLdrClose(hLdrMod);
    if (RT_FAILURE(rc))
        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTLdrClose failed: %Rrc\n", rc);
    return rcExit;
}