/**
 * Destroys the given config tokenizer.
 *
 * @returns nothing.
 * @param   pCfgTokenizer    The config tokenizer to destroy.
 */
static void autostartConfigTokenizerDestroy(PCFGTOKENIZER pCfgTokenizer)
{
    if (pCfgTokenizer->pszLine)
        RTMemFree(pCfgTokenizer->pszLine);
    if (pCfgTokenizer->hStrmConfig)
        RTStrmClose(pCfgTokenizer->hStrmConfig);
    if (pCfgTokenizer->pTokenNext)
        RTMemFree(pCfgTokenizer->pTokenNext);
    RTMemFree(pCfgTokenizer);
}
RTR3DECL(bool) RTProcIsRunningByName(const char *pszName)
{
    /*
     * Quick validation.
     */
    if (!pszName)
        return false;

    bool const fWithPath = RTPathHavePath(pszName);

    /*
     * Enumerate /proc.
     */
    RTDIR hDir;
    int rc = RTDirOpen(&hDir, "/proc");
    AssertMsgRCReturn(rc, ("RTDirOpen on /proc failed: rc=%Rrc\n", rc), false);
    if (RT_SUCCESS(rc))
    {
        RTDIRENTRY DirEntry;
        while (RT_SUCCESS(RTDirRead(hDir, &DirEntry, NULL)))
        {
            /*
             * Filter numeric directory entries only.
             */
            if (   (   DirEntry.enmType == RTDIRENTRYTYPE_DIRECTORY
                    || DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
                && RTStrToUInt32(DirEntry.szName) > 0)
            {
                /*
                 * Try readlink on exe first since it's more faster and reliable.
                 * Fall back on reading the first line in cmdline if that fails
                 * (access errors typically). cmdline is unreliable as it might
                 * contain whatever the execv caller passes as argv[0].
                 */
                char szName[RTPATH_MAX];
                RTStrPrintf(szName, sizeof(szName), "/proc/%s/exe", &DirEntry.szName[0]);
                char szExe[RTPATH_MAX];
                int cchLink = readlink(szName, szExe, sizeof(szExe) - 1);
                if (    cchLink > 0
                    &&  (size_t)cchLink < sizeof(szExe))
                {
                    szExe[cchLink] = '\0';
                    rc = VINF_SUCCESS;
                }
                else
                {
                    RTStrPrintf(szName, sizeof(szName), "/proc/%s/cmdline", &DirEntry.szName[0]);
                    PRTSTREAM pStream;
                    rc = RTStrmOpen(szName, "r", &pStream);
                    if (RT_SUCCESS(rc))
                    {
                        rc = RTStrmGetLine(pStream, szExe, sizeof(szExe));
                        RTStrmClose(pStream);
                    }
                }
                if (RT_SUCCESS(rc))
                {
                    /*
                     * We are interested on the file name part only.
                     */
                    char const *pszProcName = fWithPath ? szExe : RTPathFilename(szExe);
                    if (RTStrCmp(pszProcName, pszName) == 0)
                    {
                        /* Found it! */
                        RTDirClose(hDir);
                        return true;
                    }
                }
            }
        }
        RTDirClose(hDir);
    }

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

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

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

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

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

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

    if (gCtx.pfnGetPerformanceInfo)
    {
        PERFORMANCE_INFORMATION perfInfo;

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

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

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

            Sleep(250);

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

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

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

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

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

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

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

    RTMemFree(pProcInfo);

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        kstat_close(pStatKern);
    }

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

#endif
}
int main(int argc, char *argv[])
{
    /*
     * Initialize IPRT and convert argv to UTF-8.
     */
    int rc = RTR3InitExe(argc, &argv, 0);
    if (RT_FAILURE(rc))
        return RTMsgInitFailure(rc);

    /*
     * Parse arguments and read input files.
     */
    if (argc < 4)
    {
        usage(stderr, argv[0]);
        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Insufficient arguments.");
    }
    g_products.reserve(20000);
    g_vendors.reserve(3500);

    const char *pszOutFile = NULL;
    for (int i = 1; i < argc; i++)
    {
        if (strcmp(argv[i], "-o") == 0)
        {
            pszOutFile = argv[++i];
            continue;
        }
        if (   strcmp(argv[i], "-h") == 0
            || strcmp(argv[i], "-?") == 0
            || strcmp(argv[i], "--help") == 0)
        {
            usage(stdout, argv[0]);
            return RTEXITCODE_SUCCESS;
        }

        PRTSTREAM pInStrm;
        rc = RTStrmOpen(argv[i], "r", &pInStrm);
        if (RT_FAILURE(rc))
            return RTMsgErrorExit((RTEXITCODE)ERROR_OPEN_FILE,
                                  "Failed to open file '%s' for reading: %Rrc", argv[i], rc);

        rc = ParseUsbIds(pInStrm, argv[i]);
        RTStrmClose(pInStrm);
        if (rc != 0)
        {
            RTMsgError("Failed parsing USB devices file '%s'", argv[i]);
            return rc;
        }
    }

    /*
     * Due to USBIDDBVENDOR::iProduct, there is currently a max of 64KB products.
     * (Not a problem as we've only have less that 54K products currently.)
     */
    if (g_products.size() > _64K)
        return RTMsgErrorExit((RTEXITCODE)ERROR_TOO_MANY_PRODUCTS,
                              "More than 64K products is not supported: %u products", g_products.size());

    /*
     * Sort the IDs and fill in the iProduct and cProduct members.
     */
    sort(g_products.begin(), g_products.end());
    sort(g_vendors.begin(), g_vendors.end());

    size_t iProduct = 0;
    for (size_t iVendor = 0; iVendor < g_vendors.size(); iVendor++)
    {
        size_t const idVendor = g_vendors[iVendor].vendorID;
        g_vendors[iVendor].iProduct = iProduct;
        if (   iProduct < g_products.size()
            && g_products[iProduct].vendorID <= idVendor)
        {
            if (g_products[iProduct].vendorID == idVendor)
                do
                    iProduct++;
                while (   iProduct < g_products.size()
                       && g_products[iProduct].vendorID == idVendor);
            else
                return RTMsgErrorExit((RTEXITCODE)ERROR_IN_PARSE_LINE, "product without vendor after sorting. impossible!");
        }
        g_vendors[iVendor].cProducts = iProduct - g_vendors[iVendor].iProduct;
    }

    /*
     * Verify that all IDs are unique.
     */
    ProductsSet::iterator ita = adjacent_find(g_products.begin(), g_products.end());
    if (ita != g_products.end())
        return RTMsgErrorExit((RTEXITCODE)ERROR_DUPLICATE_ENTRY, "Duplicate alias detected: idProduct=%#06x", ita->productID);

    /*
     * Build the string table.
     * Do string compression and create the string table.
     */
    BLDPROGSTRTAB StrTab;
    if (!BldProgStrTab_Init(&StrTab, g_products.size() + g_vendors.size()))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Out of memory!");

    for (ProductsSet::iterator it = g_products.begin(); it != g_products.end(); ++it)
    {
        it->StrRef.pszString = (char *)it->str.c_str();
        BldProgStrTab_AddString(&StrTab, &it->StrRef);
    }
    for (VendorsSet::iterator it = g_vendors.begin(); it != g_vendors.end(); ++it)
    {
        it->StrRef.pszString = (char *)it->str.c_str();
        BldProgStrTab_AddString(&StrTab, &it->StrRef);
    }

    if (!BldProgStrTab_CompileIt(&StrTab, g_fVerbose))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "BldProgStrTab_CompileIt failed!\n");

    /*
     * Print stats.  Making a little extra effort to get it all on one line.
     */
    size_t const cbVendorEntry  = sizeof(USBIdDatabase::s_aVendors[0]) + sizeof(USBIdDatabase::s_aVendorNames[0]);
    size_t const cbProductEntry = sizeof(USBIdDatabase::s_aProducts[0]) + sizeof(USBIdDatabase::s_aProductNames[0]);

    size_t cbOldRaw = (g_products.size() + g_vendors.size()) * sizeof(const char *) * 2 + g_cbRawStrings;
    size_t cbRaw    = g_vendors.size() * cbVendorEntry + g_products.size() * cbProductEntry + g_cbRawStrings;
    size_t cbActual = g_vendors.size() * cbVendorEntry + g_products.size() * cbProductEntry + StrTab.cchStrTab;
#ifdef USB_ID_DATABASE_WITH_COMPRESSION
    cbActual += sizeof(StrTab.aCompDict);
#endif

    char szMsg1[32];
    RTStrPrintf(szMsg1, sizeof(szMsg1),"Total %zu bytes", cbActual);
    char szMsg2[64];
    RTStrPrintf(szMsg2, sizeof(szMsg2)," old version %zu bytes + relocs (%zu%% save)",
                cbOldRaw, (cbOldRaw - cbActual) * 100 / cbOldRaw);
    if (cbActual < cbRaw)
        RTMsgInfo("%s - saving %zu%% (%zu bytes);%s", szMsg1, (cbRaw - cbActual) * 100 / cbRaw, cbRaw - cbActual, szMsg2);
    else
        RTMsgInfo("%s - wasting %zu bytes;%s", szMsg1, cbActual - cbRaw, szMsg2);

    /*
     * Produce the source file.
     */
    if (!pszOutFile)
        return RTMsgErrorExit((RTEXITCODE)ERROR_OPEN_FILE, "Output file is not specified.");

    FILE *pOut = fopen(pszOutFile, "w");
    if (!pOut)
        return RTMsgErrorExit((RTEXITCODE)ERROR_OPEN_FILE, "Error opening '%s' for writing", pszOutFile);

    WriteSourceFile(pOut, argv[0], &StrTab);

    if (ferror(pOut))
        return RTMsgErrorExit((RTEXITCODE)ERROR_OPEN_FILE, "Error writing '%s'!", pszOutFile);
    if (fclose(pOut) != 0)
        return RTMsgErrorExit((RTEXITCODE)ERROR_OPEN_FILE, "Error closing '%s'!", pszOutFile);

    return RTEXITCODE_SUCCESS;
}
Example #5
0
int main(int argc, char **argv)
{
     RTR3InitExe(argc, &argv, 0);

     RTDIGESTTYPE enmDigestType  = RTDIGESTTYPE_INVALID;
     const char  *pszDigestType  = "NotSpecified";

     enum
     {
         kMethod_Full,
         kMethod_Block,
         kMethod_File,
         kMethod_CVAS
     } enmMethod = kMethod_Block;

     uint64_t   offStart    = 0;
     uint64_t   cbMax       = UINT64_MAX;
     bool       fTestcase   = false;

     static const RTGETOPTDEF s_aOptions[] =
     {
         { "--type",   't', RTGETOPT_REQ_STRING },
         { "--method", 'm', RTGETOPT_REQ_STRING },
         { "--help",   'h', RTGETOPT_REQ_NOTHING },
         { "--length", 'l', RTGETOPT_REQ_UINT64 },
         { "--offset", 'o', RTGETOPT_REQ_UINT64 },
         { "--testcase", 'x', RTGETOPT_REQ_NOTHING },
     };

     int ch;
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
     RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
     while ((ch = RTGetOpt(&GetState, &ValueUnion)))
     {
         switch (ch)
         {
             case 't':
                 if (!RTStrICmp(ValueUnion.psz, "crc32"))
                 {
                     pszDigestType  = "CRC32";
                     enmDigestType  = RTDIGESTTYPE_CRC32;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "crc64"))
                 {
                     pszDigestType = "CRC64";
                     enmDigestType = RTDIGESTTYPE_CRC64;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "md2"))
                 {
                     pszDigestType = "MD2";
                     enmDigestType = RTDIGESTTYPE_MD2;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "md5"))
                 {
                     pszDigestType = "MD5";
                     enmDigestType = RTDIGESTTYPE_MD5;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha1"))
                 {
                     pszDigestType = "SHA-1";
                     enmDigestType = RTDIGESTTYPE_SHA1;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha224"))
                 {
                     pszDigestType = "SHA-224";
                     enmDigestType = RTDIGESTTYPE_SHA224;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha256"))
                 {
                     pszDigestType = "SHA-256";
                     enmDigestType = RTDIGESTTYPE_SHA256;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha384"))
                 {
                     pszDigestType = "SHA-384";
                     enmDigestType = RTDIGESTTYPE_SHA384;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha512"))
                 {
                     pszDigestType = "SHA-512";
                     enmDigestType = RTDIGESTTYPE_SHA512;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha512/224"))
                 {
                     pszDigestType = "SHA-512/224";
                     enmDigestType = RTDIGESTTYPE_SHA512T224;
                 }
                 else if (!RTStrICmp(ValueUnion.psz, "sha512/256"))
                 {
                     pszDigestType = "SHA-512/256";
                     enmDigestType = RTDIGESTTYPE_SHA512T256;
                 }
                 else
                 {
                     Error("Invalid digest type: %s\n", ValueUnion.psz);
                     return 1;
                 }
                 break;

             case 'm':
                 if (!RTStrICmp(ValueUnion.psz, "full"))
                     enmMethod = kMethod_Full;
                 else if (!RTStrICmp(ValueUnion.psz, "block"))
                     enmMethod = kMethod_Block;
                 else if (!RTStrICmp(ValueUnion.psz, "file"))
                     enmMethod = kMethod_File;
                 else if (!RTStrICmp(ValueUnion.psz, "cvas"))
                     enmMethod = kMethod_CVAS;
                 else
                 {
                     Error("Invalid digest method: %s\n", ValueUnion.psz);
                     return 1;
                 }
                 break;

             case 'l':
                 cbMax = ValueUnion.u64;
                 break;

             case 'o':
                 offStart = ValueUnion.u64;
                 break;

             case 'x':
                 fTestcase = true;
                 break;

             case 'h':
                 RTPrintf("usage: tstRTDigest -t <digest-type> [-o <offset>] [-l <length>] [-x] file [file2 [..]]\n");
                 return 1;

             case VINF_GETOPT_NOT_OPTION:
             {
                 if (enmDigestType == RTDIGESTTYPE_INVALID)
                     return Error("No digest type was specified\n");

                 switch (enmMethod)
                 {
                     case kMethod_Full:
                         return Error("Full file method is not implemented\n");

                     case kMethod_File:
                         if (offStart != 0 || cbMax != UINT64_MAX)
                             return Error("The -l and -o options do not work with the 'file' method.");
                         switch (enmDigestType)
                         {
                             case RTDIGESTTYPE_SHA1:
                             {
                                 char *pszDigest;
                                 int rc = RTSha1DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL);
                                 if (RT_FAILURE(rc))
                                     return Error("RTSha1Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc);
                                 RTPrintf("%s  %s\n", pszDigest, ValueUnion.psz);
                                 RTStrFree(pszDigest);
                                 break;
                             }

                             case RTDIGESTTYPE_SHA256:
                             {
                                 char *pszDigest;
                                 int rc = RTSha256DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL);
                                 if (RT_FAILURE(rc))
                                     return Error("RTSha256Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc);
                                 RTPrintf("%s  %s\n", pszDigest, ValueUnion.psz);
                                 RTStrFree(pszDigest);
                                 break;
                             }
                             default:
                                 return Error("The file method isn't implemented for this digest\n");
                         }
                         break;

                     case kMethod_Block:
                     {
                         RTFILE hFile;
                         int rc = RTFileOpen(&hFile, ValueUnion.psz, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
                         if (RT_FAILURE(rc))
                             return Error("RTFileOpen(,%s,) -> %Rrc\n", ValueUnion.psz, rc);
                         if (offStart != 0)
                         {
                             rc = RTFileSeek(hFile, offStart, RTFILE_SEEK_BEGIN, NULL);
                             if (RT_FAILURE(rc))
                                 return Error("RTFileSeek(%s,%ull) -> %Rrc\n", ValueUnion.psz, offStart, rc);
                         }

                         uint64_t cbMaxLeft = cbMax;
                         size_t  cbRead;
                         uint8_t abBuf[_64K];
                         char   *pszDigest = (char *)&abBuf[0];
                         switch (enmDigestType)
                         {
                             case RTDIGESTTYPE_CRC32:
                             {
                                 uint32_t uCRC32 = RTCrc32Start();
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     uCRC32 = RTCrc32Process(uCRC32, abBuf, cbRead);
                                 }
                                 uCRC32 = RTCrc32Finish(uCRC32);
                                 RTStrPrintf(pszDigest, sizeof(abBuf), "%08RX32", uCRC32);
                                 break;
                             }

                             case RTDIGESTTYPE_CRC64:
                             {
                                 uint64_t uCRC64 = RTCrc64Start();
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     uCRC64 = RTCrc64Process(uCRC64, abBuf, cbRead);
                                 }
                                 uCRC64 = RTCrc64Finish(uCRC64);
                                 RTStrPrintf(pszDigest, sizeof(abBuf), "%016RX64", uCRC64);
                                 break;
                             }

                             case RTDIGESTTYPE_MD2:
                             {
                                 RTMD2CONTEXT Ctx;
                                 RTMd2Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTMd2Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTMD2_HASH_SIZE];
                                 RTMd2Final(&Ctx, abDigest);
                                 RTMd2ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             case RTDIGESTTYPE_MD5:
                             {
                                 RTMD5CONTEXT Ctx;
                                 RTMd5Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTMd5Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTMD5HASHSIZE];
                                 RTMd5Final(abDigest, &Ctx);
                                 RTMd5ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             case RTDIGESTTYPE_SHA1:
                             {
                                 RTSHA1CONTEXT Ctx;
                                 RTSha1Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTSha1Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTSHA1_HASH_SIZE];
                                 RTSha1Final(&Ctx, abDigest);
                                 RTSha1ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             case RTDIGESTTYPE_SHA256:
                             {
                                 RTSHA256CONTEXT Ctx;
                                 RTSha256Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTSha256Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTSHA256_HASH_SIZE];
                                 RTSha256Final(&Ctx, abDigest);
                                 RTSha256ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             case RTDIGESTTYPE_SHA512:
                             {
                                 RTSHA512CONTEXT Ctx;
                                 RTSha512Init(&Ctx);
                                 for (;;)
                                 {
                                     rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft);
                                     if (RT_FAILURE(rc) || !cbRead)
                                         break;
                                     RTSha512Update(&Ctx, abBuf, cbRead);
                                 }
                                 uint8_t abDigest[RTSHA512_HASH_SIZE];
                                 RTSha512Final(&Ctx, abDigest);
                                 RTSha512ToString(abDigest, pszDigest, sizeof(abBuf));
                                 break;
                             }

                             default:
                                 return Error("Internal error #1\n");
                         }
                         RTFileClose(hFile);
                         if (RT_FAILURE(rc) && rc != VERR_EOF)
                         {
                             RTPrintf("Partial: %s  %s\n", pszDigest, ValueUnion.psz);
                             return Error("RTFileRead(%s) -> %Rrc\n", ValueUnion.psz, rc);
                         }

                         if (!fTestcase)
                             RTPrintf("%s  %s\n", pszDigest, ValueUnion.psz);
                         else if (offStart)
                             RTPrintf("        { &g_abRandom72KB[%#4llx], %5llu, \"%s\", \"%s %llu bytes @%llu\" },\n",
                                      offStart, cbMax - cbMaxLeft, pszDigest, pszDigestType, offStart, cbMax - cbMaxLeft);
                         else
                             RTPrintf("        { &g_abRandom72KB[0],     %5llu, \"%s\", \"%s %llu bytes\" },\n",
                                      cbMax - cbMaxLeft, pszDigest, pszDigestType, cbMax - cbMaxLeft);
                         break;
                     }


                     /*
                      * Process a SHS response file:
                      *     http://csrc.nist.gov/groups/STM/cavp/index.html#03
                      */
                     case kMethod_CVAS:
                     {
                         RTCRDIGEST hDigest;
                         int rc = RTCrDigestCreateByType(&hDigest, enmDigestType);
                         if (RT_FAILURE(rc))
                             return Error("Failed to create digest calculator for %s: %Rrc", pszDigestType, rc);

                         uint32_t const cbDigest = RTCrDigestGetHashSize(hDigest);
                         if (!cbDigest || cbDigest >= _1K)
                             return Error("Unexpected hash size: %#x\n", cbDigest);

                         PRTSTREAM pFile;
                         rc = RTStrmOpen(ValueUnion.psz, "r", &pFile);
                         if (RT_FAILURE(rc))
                             return Error("Failed to open CVAS file '%s': %Rrc", ValueUnion.psz, rc);

                         /*
                          * Parse the input file.
                          * ASSUME order: Len, Msg, MD.
                          */
                         static char    s_szLine[_256K];
                         char          *psz;
                         uint32_t       cPassed = 0;
                         uint32_t       cErrors = 0;
                         uint32_t       iLine   = 1;
                         for (;;)
                         {
                             psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc);
                             if (!psz)
                                 break;

                             /* Skip [L = 20] stuff. */
                             if (*psz == '[')
                                 continue;

                             /* Message length. */
                             uint64_t cMessageBits;
                             if (RTStrNICmp(psz, RT_STR_TUPLE("Len =")))
                                 return Error("%s(%d): Expected 'Len =' found '%.10s...'", ValueUnion.psz, iLine, psz);
                             psz = RTStrStripL(psz + 5);
                             rc = RTStrToUInt64Full(psz, 0, &cMessageBits);
                             if (rc != VINF_SUCCESS)
                                 return Error("%s(%d): Error parsing length '%s': %Rrc\n", ValueUnion.psz, iLine, psz, rc);

                             /* The message text. */
                             psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc);
                             if (!psz)
                                 return Error("%s(%d): Expected message text not EOF.", ValueUnion.psz, iLine);
                             if (RTStrNICmp(psz, RT_STR_TUPLE("Msg =")))
                                 return Error("%s(%d): Expected 'Msg =' found '%.10s...'", ValueUnion.psz, iLine, psz);
                             psz = RTStrStripL(psz + 5);

                             size_t const   cbMessage = (cMessageBits + 7) / 8;
                             static uint8_t s_abMessage[sizeof(s_szLine) / 2];
                             if (cbMessage > 0)
                             {
                                 rc = RTStrConvertHexBytes(psz, s_abMessage, cbMessage, 0 /*fFlags*/);
                                 if (rc != VINF_SUCCESS)
                                     return Error("%s(%d): Error parsing message '%.10s...': %Rrc\n",
                                                  ValueUnion.psz, iLine, psz, rc);
                             }

                             /* The message digest. */
                             psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc);
                             if (!psz)
                                 return Error("%s(%d): Expected message digest not EOF.", ValueUnion.psz, iLine);
                             if (RTStrNICmp(psz, RT_STR_TUPLE("MD =")))
                                 return Error("%s(%d): Expected 'MD =' found '%.10s...'", ValueUnion.psz, iLine, psz);
                             psz = RTStrStripL(psz + 4);

                             static uint8_t s_abExpectedDigest[_1K];
                             rc = RTStrConvertHexBytes(psz, s_abExpectedDigest, cbDigest, 0 /*fFlags*/);
                             if (rc != VINF_SUCCESS)
                                 return Error("%s(%d): Error parsing message digest '%.10s...': %Rrc\n",
                                              ValueUnion.psz, iLine, psz, rc);

                             /*
                              * Do the testing.
                              */
                             rc = RTCrDigestReset(hDigest);
                             if (rc != VINF_SUCCESS)
                                 return Error("RTCrDigestReset failed: %Rrc", rc);

                             rc = RTCrDigestUpdate(hDigest, s_abMessage, cbMessage);
                             if (rc != VINF_SUCCESS)
                                 return Error("RTCrDigestUpdate failed: %Rrc", rc);

                             static uint8_t s_abActualDigest[_1K];
                             rc = RTCrDigestFinal(hDigest, s_abActualDigest, cbDigest);
                             if (rc != VINF_SUCCESS)
                                 return Error("RTCrDigestFinal failed: %Rrc", rc);

                             if (memcmp(s_abActualDigest, s_abExpectedDigest, cbDigest) == 0)
                                 cPassed++;
                             else
                             {
                                 Error("%s(%d): Message digest mismatch. Expected %.*RThxs, got %.*RThxs.",
                                       ValueUnion.psz, iLine, cbDigest, s_abExpectedDigest, cbDigest, s_abActualDigest);
                                 cErrors++;
                             }
                         }

                         RTStrmClose(pFile);
                         if (cErrors > 0)
                             return Error("Failed: %u error%s (%u passed)", cErrors, cErrors == 1 ? "" : "s", cPassed);
                         RTPrintf("Passed %u test%s.\n", cPassed, cPassed == 1 ? "" : "s");
                         if (RT_FAILURE(rc))
                             return Error("Failed: %Rrc", rc);
                         break;
                     }

                     default:
                         return Error("Internal error #2\n");
                 }
                 break;
             }

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

     return 0;
}
Example #6
0
int rcp_parse(struct rcp_state* state, const char *filename)
{
    unsigned i;
    uint32_t flags;
    int rc;
    struct rcp_parser parser;
    flags = state->rcps_flags;

    RT_ZERO(parser);
    RT_ZERO(*state);

    state->rcps_flags = flags;

    parser.rcpp_state = state;

    /**
     * for debugging need: with RCP_STANDALONE it's possible
     * to run simplefied scenarious like
     *
     * # cat /etc/resolv.conf | rcp-test-0
     * or in lldb
     * # process launch -i /etc/resolv.conf
     */
#ifdef RCP_STANDALONE
    if (filename == NULL)
        parser.rcpp_stream = g_pStdIn;
#else
    if (filename == NULL)
        return -1;
#endif
    else
    {
        rc = RTStrmOpen(filename, "r", &parser.rcpp_stream);
        if (RT_FAILURE(rc)) return -1;
    }

    rc = rcp_parse_primary(&parser);

    if (filename != NULL)
        RTStrmClose(parser.rcpp_stream);

    if (rc == -1)
        return -1;

#ifdef RT_OS_DARWIN
    /**
     * port recolv.conf's option and IP.port are Mac OSX extentions, there're no need to care on
     * other hosts.
     */
    if (state->rcps_port == 0)
        state->rcps_port = 53;

    for(i = 0;  (state->rcps_flags & RCPSF_NO_STR2IPCONV) == 0
             && i != RCPS_MAX_NAMESERVERS; ++i)
    {
        RTNETADDR *addr = &state->rcps_nameserver[i];

        if (addr->uPort == 0)
            addr->uPort = state->rcps_port;
    }
#endif

    if (   state->rcps_domain == NULL
        && state->rcps_searchlist[0] != NULL)
        state->rcps_domain = state->rcps_searchlist[0];

    return 0;
}
Example #7
0
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;
}
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 the certificate file
     */
    if (RT_SUCCESS(rc))
        rc = RTStrmOpen(CAFILE_NAME, "w+b", &CAFile);

    if (RT_SUCCESS(rc))
    {
        /*
         * The old way:
         */

        /*
         * Fetch the 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 = RTHttpGetText(hHttp,
                               "http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem",
                               &pszBuf);
        if (RT_SUCCESS(rc) && pszBuf)
            rc = extractPCA3G5(hHttp, CAFile, (uint8_t*)pszBuf, strlen(pszBuf));
        else
            checkError(hHttp, rc, "PCA-3G5.pem");
        if (pszBuf)
        {
            RTMemFree(pszBuf);
            pszBuf = NULL;
        }

        /*
         * Fetch the root CA certificate (old one, but still very widely used)
         */
        if (RT_SUCCESS(rc))
            rc = RTHttpGetText(hHttp,
                               "http://www.verisign.com/repository/roots/root-certificates/PCA-3.pem",
                               &pszBuf);
        if (RT_SUCCESS(rc) && pszBuf)
            rc = extractPCA3(hHttp, CAFile, (uint8_t*)pszBuf, strlen(pszBuf));
        else
            checkError(hHttp, rc, "PCA-3.pem");
        if (pszBuf)
        {
            RTMemFree(pszBuf);
            pszBuf = NULL;
        }
        RTPrintf("Old way: rc=%Rrc\n", rc);

        /*
         * The new way:
         */
        void *pu8Buf;
        size_t cb;
        rc = RTHttpGetBinary(hHttp,
                             "http://www.verisign.com/support/roots.zip",
                             &pu8Buf, &cb);
        if (RT_SUCCESS(rc) && pu8Buf)
        {
            void *pvDecomp;
            size_t cbDecomp;
            rc = RTZipPkzipMemDecompress(&pvDecomp, &cbDecomp, pu8Buf, cb,
                                        "VeriSign Root Certificates/Generation 5 (G5) PCA/VeriSign Class 3 Public Primary Certification Authority - G5.pem");
            if (RT_SUCCESS(rc))
            {
                rc = extractPCA3G5(hHttp, CAFile, (uint8_t*)pvDecomp, cbDecomp);
                RTMemFree(pvDecomp);
                rc = RTZipPkzipMemDecompress(&pvDecomp, &cbDecomp, pu8Buf, cb,
                                             "VeriSign Root Certificates/Generation 1 (G1) PCAs/Class 3 Public Primary Certification Authority.pem");
                if (RT_SUCCESS(rc))
                {
                    rc = extractPCA3(hHttp, CAFile, (uint8_t*)pvDecomp, cbDecomp);
                    RTMemFree(pvDecomp);
                }
            }
        }
        else
            checkError(hHttp, rc, "roots.zip");
        RTPrintf("New way: rc=%Rrc\n", rc);
    }

    /*
     * Close the certificate file
     */
    if (CAFile)
    {
        RTStrmClose(CAFile);
        CAFile = NULL;
    }

    /*
     * Use it
     */
    if (RT_SUCCESS(rc))
        rc = RTHttpSetCAFile(hHttp, CAFILE_NAME);

    /*
     * Now try to do the actual HTTPS request
     */
    if (RT_SUCCESS(rc))
        rc = RTHttpGetText(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;
}
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;
}