/** * Converts an stringified IPv4 address into the RTNETADDRIPV4 representation. * * @todo This should be move to some generic part of the runtime. * * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on * failure. * * @param pszValue The value to convert. * @param pAddr Where to store the result. */ static int rtgetoptConvertIPv4Addr(const char *pszValue, PRTNETADDRIPV4 pAddr) { char *pszNext; int rc = RTStrToUInt8Ex(RTStrStripL(pszValue), &pszNext, 10, &pAddr->au8[0]); if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; if (*pszNext++ != '.') return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[1]); if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; if (*pszNext++ != '.') return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[2]); if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; if (*pszNext++ != '.') return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[3]); if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pszNext = RTStrStripL(pszNext); if (*pszNext) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; return VINF_SUCCESS; }
/** * Yasm style. * * @param pState The disassembler state. */ static void MyDisasYasmFormatter(PMYDISSTATE pState) { char szTmp[256]; #if 0 /* a very quick hack. */ strcpy(szTmp, RTStrStripL(strchr(pState->szLine, ':') + 1)); char *psz = strrchr(szTmp, '['); *psz = '\0'; RTStrStripR(szTmp); psz = strstr(szTmp, " ptr "); if (psz) memset(psz, ' ', 5); char *pszEnd = strchr(szTmp, '\0'); while (pszEnd - &szTmp[0] < 71) *pszEnd++ = ' '; *pszEnd = '\0'; #else size_t cch = DISFormatYasmEx(&pState->Dis, szTmp, sizeof(szTmp), DIS_FMT_FLAGS_STRICT | DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_COMMENT | DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_COMMENT | DIS_FMT_FLAGS_BYTES_SPACED, NULL, NULL); Assert(cch < sizeof(szTmp)); while (cch < 71) szTmp[cch++] = ' '; szTmp[cch] = '\0'; #endif RTPrintf(" %s ; %s", szTmp, pState->szLine); }
RTDECL(int) RTSystemQueryAvailableRam(uint64_t *pcb) { AssertPtrReturn(pcb, VERR_INVALID_POINTER); FILE *pFile = fopen("/proc/meminfo", "r"); if (pFile) { int rc = VERR_NOT_FOUND; uint64_t cbTotal = 0; uint64_t cbFree = 0; uint64_t cbBuffers = 0; uint64_t cbCached = 0; char sz[256]; while (fgets(sz, sizeof(sz), pFile)) { if (!strncmp(sz, RT_STR_TUPLE("MemTotal:"))) rc = RTStrToUInt64Ex(RTStrStripL(&sz[sizeof("MemTotal:")]), NULL, 0, &cbTotal); else if (!strncmp(sz, RT_STR_TUPLE("MemFree:"))) rc = RTStrToUInt64Ex(RTStrStripL(&sz[sizeof("MemFree:")]), NULL, 0, &cbFree); else if (!strncmp(sz, RT_STR_TUPLE("Buffers:"))) rc = RTStrToUInt64Ex(RTStrStripL(&sz[sizeof("Buffers:")]), NULL, 0, &cbBuffers); else if (!strncmp(sz, RT_STR_TUPLE("Cached:"))) rc = RTStrToUInt64Ex(RTStrStripL(&sz[sizeof("Cached:")]), NULL, 0, &cbCached); if (RT_FAILURE(rc)) break; } fclose(pFile); if (RT_SUCCESS(rc)) { *pcb = (cbFree + cbBuffers + cbCached) * _1K; return VINF_SUCCESS; } } /* * Fallback (e.g. /proc not mapped) to sysinfo. Less accurat because there * is no information about the cached memory. 'Cached:' from above is only * accessible through proc :-( */ struct sysinfo info; int rc = sysinfo(&info); if (rc == 0) { *pcb = ((uint64_t)info.freeram + info.bufferram) * info.mem_unit; return VINF_SUCCESS; } return RTErrConvertFromErrno(errno); }
RTDECL(int) RTNetStrToIPv4Addr(const char *pcszAddr, PRTNETADDRIPV4 pAddr) { char *pszNext; int rc; AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER); AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER); pcszAddr = RTStrStripL(pcszAddr); rc = rtNetStrToIPv4AddrEx(pcszAddr, pAddr, &pszNext); if (rc != VINF_SUCCESS) return VERR_INVALID_PARAMETER; pszNext = RTStrStripL(pszNext); if (*pszNext != '\0') return VERR_INVALID_PARAMETER; return VINF_SUCCESS; }
/** * Converts an stringified Ethernet MAC address into the RTMAC representation. * * @returns VINF_SUCCESS on success. * * @param pszValue The value to convert. * @param pAddr Where to store the result. */ RTDECL(int) RTNetStrToMacAddr(const char *pszValue, PRTMAC pAddr) { /* * Not quite sure if I should accept stuff like "08::27:::1" here... * The code is accepting "::" patterns now, except for for the first * and last parts. */ /* first */ char *pszNext; int rc = RTStrToUInt8Ex(RTStrStripL(pszValue), &pszNext, 16, &pAddr->au8[0]); if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; if (*pszNext++ != ':') return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; /* middle */ for (unsigned i = 1; i < 5; i++) { if (*pszNext == ':') pAddr->au8[i] = 0; else { rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[i]); if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS) return rc; if (*pszNext != ':') return VERR_INVALID_PARAMETER; } pszNext++; } /* last */ rc = RTStrToUInt8Ex(pszNext, &pszNext, 16, &pAddr->au8[5]); if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES) return rc; pszNext = RTStrStripL(pszNext); if (*pszNext) return VERR_INVALID_PARAMETER; return VINF_SUCCESS; }
RTDECL(int) RTNetStrToIPv6Addr(const char *pcszAddr, PRTNETADDRIPV6 pAddr, char **ppszZone) { int rc; AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER); AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER); AssertPtrReturn(ppszZone, VERR_INVALID_PARAMETER); pcszAddr = RTStrStripL(pcszAddr); rc = rtNetStrToIPv6AddrEx(pcszAddr, pAddr, ppszZone, NULL); if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES) return VERR_INVALID_PARAMETER; return VINF_SUCCESS; }
/** * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate} */ static DECLCALLBACK(int) rtVfsChainGzip_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec, PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo) { RT_NOREF(pProviderReg); /* * Basics. */ if (pElement->enmType != RTVFSOBJTYPE_IO_STREAM) return VERR_VFS_CHAIN_ONLY_IOS; if (pElement->enmTypeIn == RTVFSOBJTYPE_INVALID) return VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT; if ( pElement->enmTypeIn != RTVFSOBJTYPE_FILE && pElement->enmTypeIn != RTVFSOBJTYPE_IO_STREAM) return VERR_VFS_CHAIN_TAKES_FILE_OR_IOS; if (pSpec->fOpenFile & RTFILE_O_READ) return VERR_VFS_CHAIN_WRITE_ONLY_IOS; if (pElement->cArgs > 1) return VERR_VFS_CHAIN_AT_MOST_ONE_ARG; /* * Optional argument 1..9 indicating the compression level. * We store it in pSpec->uProvider. */ if (pElement->cArgs > 0) { const char *psz = pElement->paArgs[0].psz; if (!*psz || !strcmp(psz, "default")) pElement->uProvider = 6; else if (!strcmp(psz, "fast")) pElement->uProvider = 3; else if ( RT_C_IS_DIGIT(*psz) && *psz != '0' && *RTStrStripL(psz + 1) == '\0') pElement->uProvider = *psz - '0'; else { *poffError = pElement->paArgs[0].offSpec; return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected compression level: 1-9, default, or fast"); } } else pElement->uProvider = 6; return VINF_SUCCESS; }
static int scriptDtrReg(PVM pVM, char *pszVar, char *pszValue, void *pvUser) { NOREF(pszVar); char *pszPart2 = strchr(pszValue, ':'); if (!pszPart2) return -1; *pszPart2++ = '\0'; pszPart2 = RTStrStripL(pszPart2); pszValue = RTStrStripR(pszValue); uint32_t u32; int rc = RTStrToUInt32Ex(pszValue, NULL, 16, &u32); if (RT_FAILURE(rc)) return rc; uint16_t u16; rc = RTStrToUInt16Ex(pszPart2, NULL, 16, &u16); if (RT_FAILURE(rc)) return rc; return ((PFNSETGUESTDTR)(uintptr_t)pvUser)(pVM, u32, u16); }
/* * Input file parsing. */ static int ParseAlias(char *pszLine, size_t& id, std::string& desc) { /* First there's a hexadeciman number. */ uint32_t uVal; char *pszNext; int rc = RTStrToUInt32Ex(pszLine, &pszNext, 16, &uVal); if ( rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES || rc == VINF_SUCCESS) { /* Skip the whipespace following it and at the end of the line. */ pszNext = RTStrStripL(pszNext); if (*pszNext != '\0') { rc = RTStrValidateEncoding(pszNext); if (RT_SUCCESS(rc)) { size_t cchDesc = strlen(pszNext); if (cchDesc <= USB_ID_DATABASE_MAX_STRING) { id = uVal; desc = pszNext; g_cbRawStrings += cchDesc + 1; return RTEXITCODE_SUCCESS; } RTMsgError("String to long: %zu", cchDesc); } else RTMsgError("Invalid encoding: '%s' (rc=%Rrc)", pszNext, rc); } else RTMsgError("Error parsing '%s'", pszLine); } else RTMsgError("Error converting number at the start of '%s': %Rrc", pszLine, rc); return ERROR_IN_PARSE_LINE; }
/** * Interprets a string and assigns it to a USBFilter field. * * (This function is also used by HostUSBDeviceFilter.) * * @param aFilter The filter. * @param aIdx The field index. * @param aStr The input string. * @param aName The field name for use in the error string. * @param aErrStr Where to return the error string on failure. * * @return COM status code. * @remark The idea was to have this as a static function, but tr() doesn't wanna work without a class :-/ */ /*static*/ HRESULT USBDeviceFilter::i_usbFilterFieldFromString(PUSBFILTER aFilter, USBFILTERIDX aIdx, const Utf8Str &aValue, Utf8Str &aErrStr) { int vrc; if (aValue.isEmpty()) vrc = USBFilterSetIgnore(aFilter, aIdx); else { const char *pcszValue = aValue.c_str(); if (USBFilterIsNumericField(aIdx)) { /* Is it a lonely number? */ char *pszNext; uint64_t u64; vrc = RTStrToUInt64Ex(pcszValue, &pszNext, 16, &u64); if (RT_SUCCESS(vrc)) pszNext = RTStrStripL(pszNext); if ( vrc == VINF_SUCCESS && !*pszNext) { if (u64 > 0xffff) { // there was a bug writing out "-1" values in earlier versions, which got // written as "FFFFFFFF"; make sure we don't fail on those if (u64 == 0xffffffff) u64 = 0xffff; else { aErrStr = Utf8StrFmt(tr("The %s value '%s' is too big (max 0xFFFF)"), i_describeUSBFilterIdx(aIdx), pcszValue); return E_INVALIDARG; } } vrc = USBFilterSetNumExact(aFilter, aIdx, (uint16_t)u64, true /* fMustBePresent */); } else vrc = USBFilterSetNumExpression(aFilter, aIdx, pcszValue, true /* fMustBePresent */); } else { /* Any wildcard in the string? */ Assert(USBFilterIsStringField(aIdx)); if ( strchr(pcszValue, '*') || strchr(pcszValue, '?') /* || strchr (psz, '[') - later */ ) vrc = USBFilterSetStringPattern(aFilter, aIdx, pcszValue, true /*fMustBePresent*/); else vrc = USBFilterSetStringExact(aFilter, aIdx, pcszValue, true /*fMustBePresent*/, false /*fPurge*/); } } if (RT_FAILURE(vrc)) { if (vrc == VERR_INVALID_PARAMETER) { aErrStr = Utf8StrFmt(tr("The %s filter expression '%s' is not valid"), i_describeUSBFilterIdx(aIdx), aValue.c_str()); return E_INVALIDARG; } if (vrc == VERR_BUFFER_OVERFLOW) { aErrStr = Utf8StrFmt(tr("Insufficient expression space for the '%s' filter expression '%s'"), i_describeUSBFilterIdx(aIdx), aValue.c_str()); return E_FAIL; } AssertRC(vrc); aErrStr = Utf8StrFmt(tr("Encountered unexpected status %Rrc when setting '%s' to '%s'"), vrc, i_describeUSBFilterIdx(aIdx), aValue.c_str()); return E_FAIL; } return S_OK; }
/** * 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 }
RTDECL(int) RTManifestReadStandardEx(RTMANIFEST hManifest, RTVFSIOSTREAM hVfsIos, char *pszErr, size_t cbErr) { /* * Validate input. */ AssertPtrNull(pszErr); if (pszErr && cbErr) *pszErr = '\0'; RTMANIFESTINT *pThis = hManifest; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE); /* * Process the stream line by line. */ uint32_t iLine = 0; for (;;) { /* * Read a line from the input stream. */ iLine++; char szLine[RTPATH_MAX + RTSHA512_DIGEST_LEN + 32]; int rc = rtManifestReadLine(hVfsIos, szLine, sizeof(szLine)); if (RT_FAILURE(rc)) { if (rc == VERR_EOF) return VINF_SUCCESS; RTStrPrintf(pszErr, cbErr, "Error reading line #%u: %Rrc", iLine, rc); return rc; } if (rc != VINF_SUCCESS) { RTStrPrintf(pszErr, cbErr, "Line number %u is too long", iLine); return VERR_OUT_OF_RANGE; } /* * Strip it and skip if empty. */ char *psz = RTStrStrip(szLine); if (!*psz) continue; /* * Read the attribute name. */ const char * const pszAttr = psz; do psz++; while (!RT_C_IS_BLANK(*psz) && *psz); if (*psz) *psz++ = '\0'; /* * The entry name is enclosed in parenthesis and followed by a '='. */ psz = RTStrStripL(psz); if (*psz != '(') { RTStrPrintf(pszErr, cbErr, "Expected '(' after %zu on line %u", psz - szLine, iLine); return VERR_PARSE_ERROR; } const char * const pszName = ++psz; while (*psz) { if (*psz == ')') { char *psz2 = RTStrStripL(psz + 1); if (*psz2 == '=') { *psz = '\0'; psz = psz2; break; } } psz++; } if (*psz != '=') { RTStrPrintf(pszErr, cbErr, "Expected ')=' at %zu on line %u", psz - szLine, iLine); return VERR_PARSE_ERROR; } /* * The value. */ psz = RTStrStrip(psz + 1); const char * const pszValue = psz; if (!*psz) { RTStrPrintf(pszErr, cbErr, "Expected value at %zu on line %u", psz - szLine, iLine); return VERR_PARSE_ERROR; } /* * Detect attribute type and sanity check the value. */ uint32_t fType = RTMANIFEST_ATTR_UNKNOWN; static const struct { const char *pszAttr; uint32_t fType; unsigned cBits; unsigned uBase; } s_aDecAttrs[] = { { "SIZE", RTMANIFEST_ATTR_SIZE, 64, 10} }; for (unsigned i = 0; i < RT_ELEMENTS(s_aDecAttrs); i++) if (!strcmp(s_aDecAttrs[i].pszAttr, pszAttr)) { fType = s_aDecAttrs[i].fType; rc = RTStrToUInt64Full(pszValue, s_aDecAttrs[i].uBase, NULL); if (rc != VINF_SUCCESS) { RTStrPrintf(pszErr, cbErr, "Malformed value ('%s') at %zu on line %u: %Rrc", pszValue, psz - szLine, iLine, rc); return VERR_PARSE_ERROR; } break; } if (fType == RTMANIFEST_ATTR_UNKNOWN) { static const struct { const char *pszAttr; uint32_t fType; unsigned cchHex; } s_aHexAttrs[] = { { "MD5", RTMANIFEST_ATTR_MD5, RTMD5_DIGEST_LEN }, { "SHA1", RTMANIFEST_ATTR_SHA1, RTSHA1_DIGEST_LEN }, { "SHA256", RTMANIFEST_ATTR_SHA256, RTSHA256_DIGEST_LEN }, { "SHA512", RTMANIFEST_ATTR_SHA512, RTSHA512_DIGEST_LEN } }; for (unsigned i = 0; i < RT_ELEMENTS(s_aHexAttrs); i++) if (!strcmp(s_aHexAttrs[i].pszAttr, pszAttr)) { fType = s_aHexAttrs[i].fType; for (unsigned off = 0; off < s_aHexAttrs[i].cchHex; off++) if (!RT_C_IS_XDIGIT(pszValue[off])) { RTStrPrintf(pszErr, cbErr, "Expected hex digit at %zu on line %u (value '%s', pos %u)", pszValue - szLine + off, iLine, pszValue, off); return VERR_PARSE_ERROR; } break; } } /* * Finally, add it. */ rc = RTManifestEntrySetAttr(hManifest, pszName, pszAttr, pszValue, fType); if (RT_FAILURE(rc)) { RTStrPrintf(pszErr, cbErr, "RTManifestEntrySetAttr(,'%s','%s', '%s', %#x) failed on line %u: %Rrc", pszName, pszAttr, pszValue, fType, iLine, rc); return rc; } } }
static int ParseUsbIds(PRTSTREAM pInStrm, const char *pszFile) { /* * State data. */ VendorRecord vendor = { 0, 0, 0, "" }; /* * Process the file line-by-line. * * The generic format is that we have top level entries (vendors) starting * in position 0 with sub entries starting after one or more, depending on * the level, tab characters. * * Specifically, the list of vendors and their products will always start * with a vendor line followed by indented products. The first character * on the vendor line is a hex digit (four in total) that makes up the * vendor ID. The product lines equally starts with a 4 digit hex ID value. * * Other lists are assumed to have first lines that doesn't start with any * lower case hex digit. */ uint32_t iLine = 0;; for (;;) { char szLine[_4K]; int rc = RTStrmGetLine(pInStrm, szLine, sizeof(szLine)); if (RT_SUCCESS(rc)) { iLine++; /* Check for vendor line. */ char chType = szLine[0]; if ( RT_C_IS_XDIGIT(chType) && RT_C_IS_SPACE(szLine[4]) && RT_C_IS_XDIGIT(szLine[1]) && RT_C_IS_XDIGIT(szLine[2]) && RT_C_IS_XDIGIT(szLine[3]) ) { if (ParseAlias(szLine, vendor.vendorID, vendor.str) == 0) g_vendors.push_back(vendor); else return RTMsgErrorExit((RTEXITCODE)ERROR_IN_PARSE_LINE, "%s(%d): Error in parsing vendor line: '%s'", pszFile, iLine, szLine); } /* Check for product line. */ else if (szLine[0] == '\t' && vendor.vendorID != 0) { ProductRecord product = { 0, vendor.vendorID, 0, "" }; if (ParseAlias(&szLine[1], product.productID, product.str) == 0) { product.key = RT_MAKE_U32(product.productID, product.vendorID); Assert(product.vendorID == vendor.vendorID); g_products.push_back(product); } else return RTMsgErrorExit((RTEXITCODE)ERROR_IN_PARSE_LINE, "Error in parsing product line: '%s'", szLine); } /* If not a blank or comment line, it is some other kind of data. So, make sure the vendor ID is cleared so we don't try process the sub-items of in some other list as products. */ else if ( chType != '#' && chType != '\0' && *RTStrStripL(szLine) != '\0') vendor.vendorID = 0; } else if (rc == VERR_EOF) return RTEXITCODE_SUCCESS; else return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTStrmGetLine failed: %Rrc", rc); } }
RTDECL(int) RTSha384FromString(char const *pszDigest, uint8_t pabDigest[RTSHA384_HASH_SIZE]) { return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabDigest[0], RTSHA384_HASH_SIZE, 0 /*fFlags*/); }
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; }