/** * Device I/O Control entry point. * * @returns Darwin for slow IOCtls and VBox status code for the fast ones. * @param Dev The device number (major+minor). * @param iCmd The IOCtl command. * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)). * @param fFlags Flag saying we're a character device (like we didn't know already). * @param pProcess The process issuing this request. */ static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess) { uint32_t cbReq = IOCPARM_LEN(iCmd); PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)pData; int rc; Log(("VBoxNetAdpDarwinIOCtl: param len %#x; iCmd=%#lx\n", cbReq, iCmd)); switch (IOCBASECMD(iCmd)) { case IOCBASECMD(VBOXNETADP_CTL_ADD): { if ( (IOC_DIRMASK & iCmd) != IOC_INOUT || cbReq < sizeof(VBOXNETADPREQ)) return EINVAL; PVBOXNETADP pNew; Log(("VBoxNetAdpDarwinIOCtl: szName=%s\n", pReq->szName)); rc = vboxNetAdpCreate(&pNew, pReq->szName[0] && RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))) ? pReq->szName : NULL); if (RT_FAILURE(rc)) return rc == VERR_OUT_OF_RESOURCES ? ENOMEM : EINVAL; Assert(strlen(pReq->szName) < sizeof(pReq->szName)); strncpy(pReq->szName, pNew->szName, sizeof(pReq->szName) - 1); pReq->szName[sizeof(pReq->szName) - 1] = '\0'; Log(("VBoxNetAdpDarwinIOCtl: Added '%s'\n", pReq->szName)); break; } case IOCBASECMD(VBOXNETADP_CTL_REMOVE): { if (!RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName)))) return EINVAL; PVBOXNETADP pAdp = vboxNetAdpFindByName(pReq->szName); if (!pAdp) return EINVAL; rc = vboxNetAdpDestroy(pAdp); if (RT_FAILURE(rc)) return EINVAL; Log(("VBoxNetAdpDarwinIOCtl: Removed %s\n", pReq->szName)); break; } default: printf("VBoxNetAdpDarwinIOCtl: unknown command %lx.\n", IOCBASECMD(iCmd)); return EINVAL; } return 0; }
RTDECL(int) RTStrATruncateTag(char **ppsz, size_t cchNew, const char *pszTag) { char *pszNew; char *pszOld = *ppsz; if (!cchNew) { if (pszOld && *pszOld) { *pszOld = '\0'; pszNew = (char *)RTMemReallocTag(pszOld, 1, pszTag); if (pszNew) *ppsz = pszNew; } } else { char *pszZero; AssertPtrReturn(pszOld, VERR_OUT_OF_RANGE); AssertReturn(cchNew < ~(size_t)64, VERR_OUT_OF_RANGE); pszZero = RTStrEnd(pszOld, cchNew + 63); AssertReturn(!pszZero || (size_t)(pszZero - pszOld) >= cchNew, VERR_OUT_OF_RANGE); pszOld[cchNew] = '\0'; if (!pszZero) { pszNew = (char *)RTMemReallocTag(pszOld, cchNew + 1, pszTag); if (pszNew) *ppsz = pszNew; } } return VINF_SUCCESS; }
/** * Deregisters a guest OS digger previously registered by DBGFR3OSRegister. * * @returns VBox status code. * * @param pVM Pointer to the shared VM structure. * @param pReg The registration structure. * @thread Any. */ VMMR3DECL(int) DBGFR3OSDeregister(PVM pVM, PCDBGFOSREG pReg) { /* * Validate input. */ VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pReg, VERR_INVALID_POINTER); AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC); AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC); AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME); DBGF_OS_READ_LOCK(pVM); PDBGFOS pOS; for (pOS = pVM->dbgf.s.pOSHead; pOS; pOS = pOS->pNext) if (pOS->pReg == pReg) break; DBGF_OS_READ_LOCK(pVM); if (!pOS) { Log(("DBGFR3OSDeregister: %s -> VERR_NOT_FOUND\n", pReg->szName)); return VERR_NOT_FOUND; } /* * Pass it on to EMT(0). */ return VMR3ReqPriorityCallWait(pVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSDeregister, 2, pVM, pReg); }
/** * Registers a guest OS digger. * * This will instantiate an instance of the digger and add it * to the list for us in the next call to DBGFR3OSDetect(). * * @returns VBox status code. * @param pVM Pointer to the shared VM structure. * @param pReg The registration structure. * @thread Any. */ VMMR3DECL(int) DBGFR3OSRegister(PVM pVM, PCDBGFOSREG pReg) { /* * Validate intput. */ VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pReg, VERR_INVALID_POINTER); AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC); AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC); AssertReturn(!pReg->fFlags, VERR_INVALID_PARAMETER); AssertReturn(pReg->cbData < _2G, VERR_INVALID_PARAMETER); AssertReturn(pReg->szName[0], VERR_INVALID_NAME); AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME); AssertPtrReturn(pReg->pfnConstruct, VERR_INVALID_POINTER); AssertPtrNullReturn(pReg->pfnDestruct, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnProbe, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnInit, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnRefresh, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnTerm, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnQueryVersion, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnQueryInterface, VERR_INVALID_POINTER); /* * Pass it on to EMT(0). */ return VMR3ReqPriorityCallWait(pVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSRegister, 2, pVM, pReg); }
/** * Read a zero terminated string from guest memory. * * @returns VBox status code. * * @param pVM Pointer to the shared VM structure. * @param idCpu The ID of the source CPU context (for the address). * @param pAddress Where to start reading. * @param pszBuf Where to store the string. * @param cchBuf The size of the buffer. */ static DECLCALLBACK(int) dbgfR3MemReadString(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf) { /* * Validate the input we use, PGM does the rest. */ if (!DBGFR3AddrIsValid(pVM, pAddress)) return VERR_INVALID_POINTER; if (!VALID_PTR(pszBuf)) return VERR_INVALID_POINTER; /* * Let dbgfR3MemRead do the job. */ int rc = dbgfR3MemRead(pVM, idCpu, pAddress, pszBuf, cchBuf); /* * Make sure the result is terminated and that overflow is signaled. * This may look a bit reckless with the rc but, it should be fine. */ if (!RTStrEnd(pszBuf, cchBuf)) { pszBuf[cchBuf - 1] = '\0'; rc = VINF_BUFFER_OVERFLOW; } /* * Handle partial reads (not perfect). */ else if (RT_FAILURE(rc)) { if (pszBuf[0]) rc = VINF_SUCCESS; } return rc; }
/** * Checks if it's a text stream. * * Not 100% proof. * * @returns true if it probably is a text file, false if not. * @param pStream The stream. Write or read, doesn't matter. */ bool ScmStreamIsText(PSCMSTREAM pStream) { if (RTStrEnd(pStream->pch, pStream->cb)) return false; if (!pStream->cb) return false; return true; }
RTDECL(const char *) RTStrCacheEnterN(RTSTRCACHE hStrCache, const char *pchString, size_t cchString) { AssertPtr(pchString); AssertReturn(cchString < _1G, NULL); Assert(!RTStrEnd(pchString, cchString)); return (const char *)RTMemPoolDupEx((RTMEMPOOL)hStrCache, pchString, cchString, 1); }
RTDECL(int) RTStrNLenEx(const char *pszString, size_t cchMax, size_t *pcch) { const char *pchEnd = RTStrEnd(pszString, cchMax); if (!pchEnd) { *pcch = cchMax; return VERR_BUFFER_OVERFLOW; } *pcch = pchEnd - pszString; return VINF_SUCCESS; }
RTDECL(char *) RTStrDupNTag(const char *pszString, size_t cchMax, const char *pszTag) { #if defined(__cplusplus) AssertPtr(pszString); #endif char const *pszEnd = RTStrEnd(pszString, cchMax); size_t cch = pszEnd ? (uintptr_t)pszEnd - (uintptr_t)pszString : cchMax; char *pszDst = (char *)RTMemAllocTag(cch + 1, pszTag); if (pszDst) { memcpy(pszDst, pszString, cch); pszDst[cch] = '\0'; } return pszDst; }
RTDECL(int) RTStrCopyEx(char *pszDst, size_t cbDst, const char *pszSrc, size_t cchMaxSrc) { const char *pszSrcEol = RTStrEnd(pszSrc, cchMaxSrc); size_t cchSrc = pszSrcEol ? (size_t)(pszSrcEol - pszSrc) : cchMaxSrc; if (RT_LIKELY(cchSrc < cbDst)) { memcpy(pszDst, pszSrc, cchSrc); pszDst[cchSrc] = '\0'; return VINF_SUCCESS; } if (cbDst != 0) { memcpy(pszDst, pszSrc, cbDst - 1); pszDst[cbDst - 1] = '\0'; } return VERR_BUFFER_OVERFLOW; }
RTDECL(int) RTStrCat(char *pszDst, size_t cbDst, const char *pszSrc) { char *pszDst2 = RTStrEnd(pszDst, cbDst); AssertReturn(pszDst2, VERR_INVALID_PARAMETER); cbDst -= pszDst2 - pszDst; size_t cchSrc = strlen(pszSrc); if (RT_LIKELY(cchSrc < cbDst)) { memcpy(pszDst2, pszSrc, cchSrc + 1); return VINF_SUCCESS; } if (cbDst != 0) { memcpy(pszDst2, pszSrc, cbDst - 1); pszDst2[cbDst - 1] = '\0'; } return VERR_BUFFER_OVERFLOW; }
RTDECL(int) RTFileOpenTemp(PRTFILE phFile, char *pszFilename, size_t cbFilename, uint64_t fOpen) { AssertReturn((fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE, VERR_INVALID_FLAGS); AssertReturn(fOpen & RTFILE_O_WRITE, VERR_INVALID_FLAGS); /* * Start by obtaining the path to the temporary directory. */ int rc = RTPathTemp(pszFilename, cbFilename); if (RT_SUCCESS(rc)) { /* * Add a filename pattern. */ static char const s_szTemplate[] = "IPRT-XXXXXXXXXXXX.tmp"; rc = RTPathAppend(pszFilename, cbFilename, s_szTemplate); if (RT_SUCCESS(rc)) { char * const pszX = RTStrEnd(pszFilename, cbFilename) - (sizeof(s_szTemplate) - 1) + 5; unsigned cXes = sizeof(s_szTemplate) - 1 - 4 - 5; Assert(pszX[0] == 'X'); Assert(pszX[-1] == '-'); Assert(pszX[cXes] == '.'); /* * Try 10000 times with random names. */ unsigned cTriesLeft = 10000; while (cTriesLeft-- > 0) { rtCreateTempFillTemplate(pszX, cXes); rc = RTFileOpen(phFile, pszFilename, fOpen); if (RT_SUCCESS(rc)) return rc; } } } if (cbFilename) *pszFilename = '\0'; *phFile = NIL_RTFILE; return rc; }
/** * @copydoc DBGFOSREG::pfnQueryVersion */ static DECLCALLBACK(int) dbgDiggerLinuxQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion) { PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData; Assert(pThis->fValid); /* * It's all in the linux banner. */ int rc = DBGFR3MemReadString(pUVM, 0, &pThis->AddrLinuxBanner, pszVersion, cchVersion); if (RT_SUCCESS(rc)) { char *pszEnd = RTStrEnd(pszVersion, cchVersion); AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW); while ( pszEnd > pszVersion && RT_C_IS_SPACE(pszEnd[-1])) pszEnd--; *pszEnd = '\0'; } else RTStrPrintf(pszVersion, cchVersion, "DBGFR3MemRead -> %Rrc", rc); return rc; }
RTDECL(int) RTStrCopyPEx(char **ppszDst, size_t *pcbDst, const char *pszSrc, size_t cchMaxSrc) { const char *pszSrcEol = RTStrEnd(pszSrc, cchMaxSrc); size_t cchSrc = pszSrcEol ? (size_t)(pszSrcEol - pszSrc) : cchMaxSrc; size_t const cbDst = *pcbDst; char *pszDst = *ppszDst; if (RT_LIKELY(cchSrc < cbDst)) { memcpy(pszDst, pszSrc, cchSrc); *ppszDst = pszDst += cchSrc; *pszDst = '\0'; *pcbDst -= cchSrc; return VINF_SUCCESS; } if (cbDst != 0) { memcpy(*ppszDst, pszSrc, cbDst - 1); *ppszDst = pszDst += cbDst - 1; *pszDst = '\0'; *pcbDst = 1; } return VERR_BUFFER_OVERFLOW; }
/** * Create one directory and any missing parent directories. * * @returns exit code * @param pOpts The mkdir option. * @param pszDir The path to the new directory. */ static int rtCmdRmDirOneWithParents(RTCMDRMDIROPTS const *pOpts, const char *pszDir) { /* We need a copy we can work with here. */ char *pszCopy = RTStrDup(pszDir); if (!pszCopy) return RTMsgErrorExitFailure("Out of string memory!"); int rc; if (!pOpts->fAlwaysUseChainApi && !RTVfsChainIsSpec(pszDir) ) { size_t cchCopy = strlen(pszCopy); do { rc = RTDirRemove(pszCopy); if (RT_SUCCESS(rc)) { if (pOpts->fVerbose) RTPrintf("%s\n", pszCopy); } else if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting) rc = VINF_SUCCESS; else { if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty) rc = VINF_SUCCESS; else RTMsgError("Failed to remove directory '%s': %Rrc", pszCopy, rc); break; } /* Strip off a component. */ while (cchCopy > 0 && RTPATH_IS_SLASH(pszCopy[cchCopy - 1])) cchCopy--; while (cchCopy > 0 && !RTPATH_IS_SLASH(pszCopy[cchCopy - 1])) cchCopy--; while (cchCopy > 0 && RTPATH_IS_SLASH(pszCopy[cchCopy - 1])) cchCopy--; pszCopy[cchCopy] = '\0'; } while (cchCopy > 0); } else { /* * Strip the final path element from the pszDir spec. */ char *pszFinalPath; char *pszSpec; uint32_t offError; rc = RTVfsChainSplitOffFinalPath(pszCopy, &pszSpec, &pszFinalPath, &offError); if (RT_SUCCESS(rc)) { /* * Open the root director/whatever. */ RTERRINFOSTATIC ErrInfo; RTVFSDIR hVfsBaseDir; if (pszSpec) { rc = RTVfsChainOpenDir(pszSpec, 0 /*fOpen*/, &hVfsBaseDir, &offError, RTErrInfoInitStatic(&ErrInfo)); if (RT_FAILURE(rc)) RTVfsChainMsgError("RTVfsChainOpenDir", pszSpec, rc, offError, &ErrInfo.Core); else if (!pszFinalPath) pszFinalPath = RTStrEnd(pszSpec, RTSTR_MAX); } else if (!RTPathStartsWithRoot(pszFinalPath)) { rc = RTVfsDirOpenNormal(".", 0 /*fOpen*/, &hVfsBaseDir); if (RT_FAILURE(rc)) RTMsgError("Failed to open '.' (for %s): %Rrc", rc, pszFinalPath); } else { char *pszRoot = pszFinalPath; pszFinalPath = RTPathSkipRootSpec(pszFinalPath); char const chSaved = *pszFinalPath; *pszFinalPath = '\0'; rc = RTVfsDirOpenNormal(pszRoot, 0 /*fOpen*/, &hVfsBaseDir); *pszFinalPath = chSaved; if (RT_FAILURE(rc)) RTMsgError("Failed to open root dir for '%s': %Rrc", rc, pszRoot); } /* * Walk the path component by component, starting at the end. */ if (RT_SUCCESS(rc)) { size_t cchFinalPath = strlen(pszFinalPath); while (RT_SUCCESS(rc) && cchFinalPath > 0) { rc = RTVfsDirRemoveDir(hVfsBaseDir, pszFinalPath, 0 /*fFlags*/); if (RT_SUCCESS(rc)) { if (pOpts->fVerbose) RTPrintf("%s\n", pszCopy); } else if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting) rc = VINF_SUCCESS; else { if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty) rc = VINF_SUCCESS; else if (pszSpec) RTMsgError("Failed to remove directory '%s:%s': %Rrc", pszSpec, pszFinalPath, rc); else RTMsgError("Failed to remove directory '%s': %Rrc", pszFinalPath, rc); break; } /* Strip off a component. */ while (cchFinalPath > 0 && RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1])) cchFinalPath--; while (cchFinalPath > 0 && !RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1])) cchFinalPath--; while (cchFinalPath > 0 && RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1])) cchFinalPath--; pszFinalPath[cchFinalPath] = '\0'; } RTVfsDirRelease(hVfsBaseDir); } } else RTVfsChainMsgError("RTVfsChainOpenParentDir", pszCopy, rc, offError, NULL); } RTStrFree(pszCopy); return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; }
RTDECL(size_t) RTStrNLen(const char *pszString, size_t cchMax) { const char *pchEnd = RTStrEnd(pszString, cchMax); return pchEnd ? pchEnd - pszString : cchMax; }
RTDECL(int) RTDirCreateUniqueNumbered(char *pszPath, size_t cbSize, RTFMODE fMode, signed int cchDigits, char chSep) { /* * Validate input. */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(cbSize, VERR_BUFFER_OVERFLOW); AssertReturn(cchDigits > 0, VERR_INVALID_PARAMETER); /* Check that there is sufficient space. */ char *pszEnd = RTStrEnd(pszPath, cbSize); AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW); AssertReturn(cbSize - 1 - (pszEnd - pszPath) >= (size_t)cchDigits + (chSep ? 1 : 0), VERR_BUFFER_OVERFLOW); size_t cbLeft = cbSize - (pszEnd - pszPath); /* First try is to create the path without any numbers. */ int rc = RTDirCreate(pszPath, fMode, 0); if ( RT_SUCCESS(rc) || rc != VERR_ALREADY_EXISTS) return rc; /* If the separator value isn't zero, add it. */ if (chSep != '\0') { cbLeft--; *pszEnd++ = chSep; *pszEnd = '\0'; } /* How many tries? Stay within somewhat sane limits. */ uint32_t cMaxTries; if (cchDigits >= 8) cMaxTries = 100 * _1M; else { cMaxTries = 10; for (int a = 0; a < cchDigits - 1; ++a) cMaxTries *= 10; } /* Try cMaxTries - 1 times to create a directory with appended numbers. */ uint32_t i = 1; while (i < cMaxTries) { /* Format the number with leading zero's. */ ssize_t rc2 = RTStrFormatU32(pszEnd, cbLeft, i, 10, cchDigits, 0, RTSTR_F_WIDTH | RTSTR_F_ZEROPAD); if (RT_FAILURE((int) rc2)) { *pszPath = '\0'; return (int)rc2; } rc = RTDirCreate(pszPath, fMode, 0); if (RT_SUCCESS(rc)) return rc; ++i; } /* We've given up. */ *pszPath = '\0'; return VERR_ALREADY_EXISTS; }
RTDECL(int) RTPathAppendEx(char *pszPath, size_t cbPathDst, const char *pszAppend, size_t cchAppendMax) { char *pszPathEnd = RTStrEnd(pszPath, cbPathDst); AssertReturn(pszPathEnd, VERR_INVALID_PARAMETER); /* * Special cases. */ if (!pszAppend) return VINF_SUCCESS; size_t cchAppend = RTStrNLen(pszAppend, cchAppendMax); if (!cchAppend) return VINF_SUCCESS; if (pszPathEnd == pszPath) { if (cchAppend >= cbPathDst) return VERR_BUFFER_OVERFLOW; memcpy(pszPath, pszAppend, cchAppend); pszPath[cchAppend] = '\0'; return VINF_SUCCESS; } /* * Balance slashes and check for buffer overflow. */ if (!RTPATH_IS_SLASH(pszPathEnd[-1])) { if (!RTPATH_IS_SLASH(pszAppend[0])) { #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) if ( (size_t)(pszPathEnd - pszPath) == 2 && pszPath[1] == ':' && RT_C_IS_ALPHA(pszPath[0])) { if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cbPathDst) return VERR_BUFFER_OVERFLOW; } else #endif { if ((size_t)(pszPathEnd - pszPath) + 1 + cchAppend >= cbPathDst) return VERR_BUFFER_OVERFLOW; *pszPathEnd++ = RTPATH_SLASH; } } else { /* One slash is sufficient at this point. */ while (cchAppend > 1 && RTPATH_IS_SLASH(pszAppend[1])) pszAppend++, cchAppend--; if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cbPathDst) return VERR_BUFFER_OVERFLOW; } } else { /* No slashes needed in the appended bit. */ while (cchAppend && RTPATH_IS_SLASH(*pszAppend)) pszAppend++, cchAppend--; /* In the leading path we can skip unnecessary trailing slashes, but be sure to leave one. */ size_t const cchRoot = rtPathRootSpecLen2(pszPath); while ( (size_t)(pszPathEnd - pszPath) > RT_MAX(1, cchRoot) && RTPATH_IS_SLASH(pszPathEnd[-2])) pszPathEnd--; if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cbPathDst) return VERR_BUFFER_OVERFLOW; } /* * What remains now is the just the copying. */ memcpy(pszPathEnd, pszAppend, cchAppend); pszPathEnd[cchAppend] = '\0'; return VINF_SUCCESS; }
int main() { RTTEST hTest; int rc = RTTestInitAndCreate("tstRTSystemQueryOsInfo", &hTest); if (rc) return rc; RTTestBanner(hTest); /* * Simple stuff. */ char szInfo[_4K]; rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szInfo, sizeof(szInfo)); RTTestIPrintf(RTTESTLVL_ALWAYS, "PRODUCT: \"%s\", rc=%Rrc\n", szInfo, rc); rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szInfo, sizeof(szInfo)); RTTestIPrintf(RTTESTLVL_ALWAYS, "RELEASE: \"%s\", rc=%Rrc\n", szInfo, rc); rc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szInfo, sizeof(szInfo)); RTTestIPrintf(RTTESTLVL_ALWAYS, "VERSION: \"%s\", rc=%Rrc\n", szInfo, rc); rc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szInfo, sizeof(szInfo)); RTTestIPrintf(RTTESTLVL_ALWAYS, "SERVICE_PACK: \"%s\", rc=%Rrc\n", szInfo, rc); uint64_t cbTotal; rc = RTSystemQueryTotalRam(&cbTotal); RTTestIPrintf(RTTESTLVL_ALWAYS, "Total RAM: %'RU64 Bytes (%RU64 KB, %RU64 MB)\n", cbTotal, cbTotal / _1K, cbTotal / _1M); uint64_t cbAvailable; rc = RTSystemQueryAvailableRam(&cbAvailable); RTTestIPrintf(RTTESTLVL_ALWAYS, "Available RAM: %'RU64 Bytes (%RU64 KB, %RU64 MB)\n", cbAvailable, cbAvailable / _1K, cbAvailable / _1M); /* * Check that unsupported stuff is terminated correctly. */ for (int i = RTSYSOSINFO_INVALID + 1; i < RTSYSOSINFO_END; i++) { memset(szInfo, ' ', sizeof(szInfo)); rc = RTSystemQueryOSInfo((RTSYSOSINFO)i, szInfo, sizeof(szInfo)); if ( rc == VERR_NOT_SUPPORTED && szInfo[0] != '\0') RTTestIFailed("level=%d; unterminated buffer on VERR_NOT_SUPPORTED\n", i); else if (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW) RTTESTI_CHECK(RTStrEnd(szInfo, sizeof(szInfo)) != NULL); else if (rc != VERR_NOT_SUPPORTED) RTTestIFailed("level=%d unexpected rc=%Rrc\n", i, rc); } /* * Check buffer overflow */ RTAssertSetQuiet(true); RTAssertSetMayPanic(false); for (int i = RTSYSDMISTR_INVALID + 1; i < RTSYSDMISTR_END; i++) { RTTESTI_CHECK_RC(RTSystemQueryDmiString((RTSYSDMISTR)i, szInfo, 0), VERR_INVALID_PARAMETER); /* Get the length of the info and check that we get overflow errors for everything less that it. */ rc = RTSystemQueryOSInfo((RTSYSOSINFO)i, szInfo, sizeof(szInfo)); if (RT_FAILURE(rc)) continue; size_t const cchInfo = strlen(szInfo); for (size_t cch = 1; cch < sizeof(szInfo) && cch < cchInfo; cch++) { memset(szInfo, 0x7f, sizeof(szInfo)); RTTESTI_CHECK_RC(RTSystemQueryOSInfo((RTSYSOSINFO)i, szInfo, cch), VERR_BUFFER_OVERFLOW); /* check the padding. */ for (size_t off = cch; off < sizeof(szInfo); off++) if (szInfo[off] != 0x7f) { RTTestIFailed("level=%d, rc=%Rrc, cch=%zu, off=%zu: Wrote too much!\n", i, rc, cch, off); break; } /* check for zero terminator. */ if (!RTStrEnd(szInfo, cch)) RTTestIFailed("level=%d, rc=%Rrc, cch=%zu: Buffer not terminated!\n", i, rc, cch); } /* Check that the exact length works. */ rc = RTSystemQueryOSInfo((RTSYSOSINFO)i, szInfo, cchInfo + 1); if (rc != VINF_SUCCESS) RTTestIFailed("level=%d: rc=%Rrc when specifying exactly right buffer length (%zu)\n", i, rc, cchInfo + 1); } return RTTestSummaryAndDestroy(hTest); }