static int scriptSysReg(PVM pVM, char *pszVar, char *pszValue, void *pvUser) { NOREF(pszVar); uint32_t u32; int rc = RTStrToUInt32Ex(pszValue, NULL, 16, &u32); if (RT_FAILURE(rc)) return rc; return ((PFNSETGUESTSYS)(uintptr_t)pvUser)(pVM, u32); }
/** * Copies the value of a node into the given integer variable. * Returns TRUE only if a value was found and was actually an * integer of the given type. * @return */ bool Node::copyValue(uint32_t &i) const { const char *pcsz; if ( ((pcsz = getValue())) && (VINF_SUCCESS == RTStrToUInt32Ex(pcsz, NULL, 10, &i)) ) return true; return false; }
/** * Convenience method which attempts to find the attribute with the given * name and returns its value as an unsigned integer.This calls * RTStrToUInt32Ex internally and will only output the integer if that * function returns no error. * * @param pcszMatch name of attribute to find (see findAttribute() for namespace remarks) * @param i out: attribute value; overwritten only if attribute was found * @return TRUE if attribute was found and str was thus updated. */ bool ElementNode::getAttributeValue(const char *pcszMatch, uint32_t &i) const { const char *pcsz; if ( (getAttributeValue(pcszMatch, pcsz)) && (VINF_SUCCESS == RTStrToUInt32Ex(pcsz, NULL, 0, &i)) ) return true; return false; }
RTDECL(dev_t) RTLinuxSysFsReadDevNumFileV(const char *pszFormat, va_list va) { int fd = RTLinuxSysFsOpenV(pszFormat, va); if (fd == -1) return 0; dev_t DevNum = 0; char szNum[128]; ssize_t cchNum = RTLinuxSysFsReadStr(fd, szNum, sizeof(szNum)); if (cchNum > 0) { uint32_t u32Maj = 0; uint32_t u32Min = 0; char *pszNext = NULL; int rc = RTStrToUInt32Ex(szNum, &pszNext, 10, &u32Maj); if (RT_FAILURE(rc) || (rc != VWRN_TRAILING_CHARS) || (*pszNext != ':')) errno = EINVAL; else { rc = RTStrToUInt32Ex(pszNext + 1, NULL, 10, &u32Min); if ( rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES) errno = EINVAL; else { errno = 0; DevNum = makedev(u32Maj, u32Min); } } } else if (cchNum == 0) errno = EINVAL; RTLinuxSysFsClose(fd); return DevNum; }
/** Check if the host kernel supports VT-x or not. * * Older Linux kernels clear the VMXE bit in the CR4 register (function * tlb_flush_all()) leading to a host kernel panic. */ int suplibOsQueryVTxSupported(void) { char szBuf[256]; int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szBuf, sizeof(szBuf)); if (RT_SUCCESS(rc)) { char *pszNext; uint32_t uA, uB, uC; rc = RTStrToUInt32Ex(szBuf, &pszNext, 10, &uA); if ( RT_SUCCESS(rc) && *pszNext == '.') { /* * new version number scheme starting with Linux 3.0 */ if (uA >= 3) return VINF_SUCCESS; rc = RTStrToUInt32Ex(pszNext+1, &pszNext, 10, &uB); if ( RT_SUCCESS(rc) && *pszNext == '.') { rc = RTStrToUInt32Ex(pszNext+1, &pszNext, 10, &uC); if (RT_SUCCESS(rc)) { uint32_t uLinuxVersion = (uA << 16) + (uB << 8) + uC; if (uLinuxVersion >= (2 << 16) + (6 << 8) + 13) return VINF_SUCCESS; } } } } return VERR_SUPDRV_KERNEL_TOO_OLD_FOR_VTX; }
/* * XXX: TODO: Share decoding code with DHCPServer::addOption. */ static int parseDhcpOptionText(const char *pszText, int *pOptCode, char **ppszOptText, int *pOptEncoding) { uint8_t u8Code; uint32_t u32Enc; char *pszNext; int rc; rc = RTStrToUInt8Ex(pszText, &pszNext, 10, &u8Code); if (!RT_SUCCESS(rc)) return VERR_PARSE_ERROR; switch (*pszNext) { case ':': /* support legacy format too */ { u32Enc = 0; break; } case '=': { u32Enc = 1; break; } case '@': { rc = RTStrToUInt32Ex(pszNext + 1, &pszNext, 10, &u32Enc); if (!RT_SUCCESS(rc)) return VERR_PARSE_ERROR; if (*pszNext != '=') return VERR_PARSE_ERROR; break; } default: return VERR_PARSE_ERROR; } *pOptCode = u8Code; *ppszOptText = pszNext + 1; *pOptEncoding = (int)u32Enc; return VINF_SUCCESS; }
/** * Gets a 32-bit value argument. * @todo Get rid of this and VBoxServiceArgString() as soon as we have RTOpt handling. * * @returns 0 on success, non-zero exit code on error. * @param argc The argument count. * @param argv The argument vector * @param psz Where in *pi to start looking for the value argument. * @param pi Where to find and perhaps update the argument index. * @param pu32 Where to store the 32-bit value. * @param u32Min The minimum value. * @param u32Max The maximum value. */ int VBoxServiceArgUInt32(int argc, char **argv, const char *psz, int *pi, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max) { if (*psz == ':' || *psz == '=') psz++; if (!*psz) { if (*pi + 1 >= argc) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing value for the '%s' argument\n", argv[*pi]); psz = argv[++*pi]; } char *pszNext; int rc = RTStrToUInt32Ex(psz, &pszNext, 0, pu32); if (RT_FAILURE(rc) || *pszNext) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Failed to convert interval '%s' to a number\n", psz); if (*pu32 < u32Min || *pu32 > u32Max) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The timesync interval of %RU32 seconds is out of range [%RU32..%RU32]\n", *pu32, u32Min, u32Max); return 0; }
/** * Reads a guest property as a 32-bit value. * * @returns VBox status code, fully bitched. * * @param u32ClientId The HGCM client ID for the guest property session. * @param pszPropName The property name. * @param pu32 Where to store the 32-bit value. * */ int VBoxServiceReadPropUInt32(uint32_t u32ClientId, const char *pszPropName, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max) { char *pszValue; int rc = VBoxServiceReadProp(u32ClientId, pszPropName, &pszValue, NULL /* ppszFlags */, NULL /* puTimestamp */); if (RT_SUCCESS(rc)) { char *pszNext; rc = RTStrToUInt32Ex(pszValue, &pszNext, 0, pu32); if ( RT_SUCCESS(rc) && (*pu32 < u32Min || *pu32 > u32Max)) { rc = VBoxServiceError("The guest property value %s = %RU32 is out of range [%RU32..%RU32].\n", pszPropName, *pu32, u32Min, u32Max); } RTStrFree(pszValue); } return rc; }
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; }
static RTEXITCODE RTCmdChMod(unsigned cArgs, char **papszArgs) { /* * Parse the command line. */ static const RTGETOPTDEF s_aOptions[] = { /* operations */ { "--recursive", 'R', RTGETOPT_REQ_NOTHING }, { "--preserve-root", 'x', RTGETOPT_REQ_NOTHING }, { "--no-preserve-root", 'X', RTGETOPT_REQ_NOTHING }, { "--changes", 'c', RTGETOPT_REQ_NOTHING }, { "--quiet", 'f', RTGETOPT_REQ_NOTHING }, { "--silent", 'f', RTGETOPT_REQ_NOTHING }, { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, { "--reference", 'Z', RTGETOPT_REQ_NOTHING }, { "--always-use-vfs-chain-api", 'A', RTGETOPT_REQ_NOTHING }, }; RTGETOPTSTATE GetState; int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOpt failed: %Rrc", rc); RTCMDCHMODOPTS Opts; Opts.enmNoiseLevel = kRTCmdChModNoise_Default; Opts.fPreserveRoot = false; Opts.fRecursive = false; Opts.fAlwaysUseChainApi = false; Opts.fModeClear = 0; Opts.fModeSet = 0; RTGETOPTUNION ValueUnion; while ( (rc = RTGetOpt(&GetState, &ValueUnion)) != 0 && rc != VINF_GETOPT_NOT_OPTION) { switch (rc) { case 'R': Opts.fRecursive = true; break; case 'x': Opts.fPreserveRoot = true; break; case 'X': Opts.fPreserveRoot = false; break; case 'f': Opts.enmNoiseLevel = kRTCmdChModNoise_Quiet; break; case 'c': Opts.enmNoiseLevel = kRTCmdChModNoise_Changes; break; case 'v': Opts.enmNoiseLevel = kRTCmdChModNoise_Verbose; break; case 'Z': { RTFSOBJINFO ObjInfo; RTERRINFOSTATIC ErrInfo; uint32_t offError; rc = RTVfsChainQueryInfo(ValueUnion.psz, &ObjInfo,RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK, &offError, RTErrInfoInitStatic(&ErrInfo)); if (RT_FAILURE(rc)) return RTVfsChainMsgErrorExitFailure("RTVfsChainQueryInfo", ValueUnion.psz, rc, offError, &ErrInfo.Core); Opts.fModeClear = RTCHMOD_SET_ALL_MASK; Opts.fModeSet = ObjInfo.Attr.fMode & RTCHMOD_SET_ALL_MASK; break; } case 'A': Opts.fAlwaysUseChainApi = true; break; case 'h': RTPrintf("Usage: %s [options] <mode> <file> [..]\n" "\n" "Options:\n" " -f, --silent, --quiet\n" " -c, --changes\n" " -v, --verbose\n" " Noise level selection.\n" " -R, --recursive\n" " Recurse into directories.\n" " --preserve-root, --no-preserve-root\n" " Whether to allow recursion from the root (default: yes).\n" " --reference <file>\n" " Take mode mask to use from <file> instead of <mode>.\n" "\n" "The <mode> part isn't fully implemented, so only numerical octal notation\n" "works. Prefix the number(s) with 0x to use hexadecimal. There are two forms\n" "of the numerical notation: <SET> and <SET>:<CLEAR>\n" , papszArgs[0]); return RTEXITCODE_SUCCESS; case 'V': RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision()); return RTEXITCODE_SUCCESS; default: return RTGetOptPrintError(rc, &ValueUnion); } } /* * The MODE. */ if ( Opts.fModeClear == 0 && Opts.fModeSet == 0) { if (rc != VINF_GETOPT_NOT_OPTION) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No mode change specified.\n"); char *pszNext; if ( ValueUnion.psz[0] == '0' && (ValueUnion.psz[1] == 'x' || ValueUnion.psz[1] == 'X')) rc = RTStrToUInt32Ex(ValueUnion.psz, &pszNext, 16, &Opts.fModeSet); else rc = RTStrToUInt32Ex(ValueUnion.psz, &pszNext, 8, &Opts.fModeSet); if ( rc != VINF_SUCCESS && (rc != VWRN_TRAILING_CHARS || *pszNext != ':')) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unable to parse mode mask: %s\n", ValueUnion.psz); Opts.fModeSet &= RTCHMOD_SET_ALL_MASK; if (rc == VINF_SUCCESS) Opts.fModeClear = RTCHMOD_SET_ALL_MASK; else { pszNext++; if ( pszNext[0] == '0' && (pszNext[1] == 'x' || pszNext[1] == 'X')) rc = RTStrToUInt32Ex(pszNext, &pszNext, 16, &Opts.fModeClear); else rc = RTStrToUInt32Ex(pszNext, &pszNext, 8, &Opts.fModeClear); if (rc != VINF_SUCCESS) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unable to parse mode mask: %s\n", ValueUnion.psz); Opts.fModeClear &= RTCHMOD_SET_ALL_MASK; } rc = RTGetOpt(&GetState, &ValueUnion); } /* * No files means error. */ if (rc != VINF_GETOPT_NOT_OPTION) return RTMsgErrorExit(RTEXITCODE_FAILURE, "No directories specified.\n"); /* * Work thru the specified dirs. */ RTEXITCODE rcExit = RTEXITCODE_SUCCESS; while (rc == VINF_GETOPT_NOT_OPTION) { if (Opts.fRecursive) rc = rtCmdChModRecursive(&Opts, ValueUnion.psz); else rc = rtCmdChModOne(&Opts, ValueUnion.psz); if (RT_FAILURE(rc)) rcExit = RTEXITCODE_FAILURE; /* next */ rc = RTGetOpt(&GetState, &ValueUnion); } if (rc != 0) rcExit = RTGetOptPrintError(rc, &ValueUnion); return rcExit; }
/** * Construct a TCP socket stream driver instance. * * @copydoc FNPDMDRVCONSTRUCT */ static DECLCALLBACK(int) drvTCPConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { RT_NOREF(fFlags); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); PDRVTCP pThis = PDMINS_2_DATA(pDrvIns, PDRVTCP); /* * Init the static parts. */ pThis->pDrvIns = pDrvIns; pThis->pszLocation = NULL; pThis->fIsServer = false; pThis->hTcpServ = NULL; pThis->hTcpSock = NIL_RTSOCKET; pThis->hPollSet = NIL_RTPOLLSET; pThis->hPipeWakeR = NIL_RTPIPE; pThis->hPipeWakeW = NIL_RTPIPE; pThis->fTcpSockInPollSet = false; pThis->ListenThread = NIL_RTTHREAD; pThis->fShutdown = false; /* IBase */ pDrvIns->IBase.pfnQueryInterface = drvTCPQueryInterface; /* IStream */ pThis->IStream.pfnPoll = drvTcpPoll; pThis->IStream.pfnPollInterrupt = drvTcpPollInterrupt; pThis->IStream.pfnRead = drvTcpRead; pThis->IStream.pfnWrite = drvTcpWrite; /* * Validate and read the configuration. */ PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "Location|IsServer", ""); int rc = CFGMR3QueryStringAlloc(pCfg, "Location", &pThis->pszLocation); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Configuration error: querying \"Location\" resulted in %Rrc"), rc); rc = CFGMR3QueryBool(pCfg, "IsServer", &pThis->fIsServer); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Configuration error: querying \"IsServer\" resulted in %Rrc"), rc); rc = RTPipeCreate(&pThis->hPipeWakeR, &pThis->hPipeWakeW, 0 /* fFlags */); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d: Failed to create wake pipe"), pDrvIns->iInstance); rc = RTPollSetCreate(&pThis->hPollSet); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d: Failed to create poll set"), pDrvIns->iInstance); rc = RTPollSetAddPipe(pThis->hPollSet, pThis->hPipeWakeR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, DRVTCP_POLLSET_ID_WAKEUP); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d failed to add wakeup pipe for %s to poll set"), pDrvIns->iInstance, pThis->pszLocation); /* * Create/Open the socket. */ if (pThis->fIsServer) { uint32_t uPort = 0; rc = RTStrToUInt32Ex(pThis->pszLocation, NULL, 10, &uPort); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d: The port part of the location is not a numerical value"), pDrvIns->iInstance); /** @todo Allow binding to distinct interfaces. */ rc = RTTcpServerCreateEx(NULL, uPort, &pThis->hTcpServ); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d failed to create server socket"), pDrvIns->iInstance); rc = RTThreadCreate(&pThis->ListenThread, drvTCPListenLoop, (void *)pThis, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "DrvTCPStream"); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d failed to create listening thread"), pDrvIns->iInstance); } else { char *pszPort = strchr(pThis->pszLocation, ':'); if (!pszPort) return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_FOUND, RT_SRC_POS, N_("DrvTCP#%d: The location misses the port to connect to"), pDrvIns->iInstance); *pszPort = '\0'; /* Overwrite temporarily to avoid copying the hostname into a temporary buffer. */ uint32_t uPort = 0; rc = RTStrToUInt32Ex(pszPort + 1, NULL, 10, &uPort); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d: The port part of the location is not a numerical value"), pDrvIns->iInstance); rc = RTTcpClientConnect(pThis->pszLocation, uPort, &pThis->hTcpSock); *pszPort = ':'; /* Restore delimiter before checking the status. */ if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d failed to connect to socket %s"), pDrvIns->iInstance, pThis->pszLocation); rc = RTPollSetAddSocket(pThis->hPollSet, pThis->hTcpSock, RTPOLL_EVT_READ | RTPOLL_EVT_WRITE | RTPOLL_EVT_ERROR, DRVTCP_POLLSET_ID_SOCKET); if (RT_FAILURE(rc)) return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("DrvTCP#%d failed to add socket for %s to poll set"), pDrvIns->iInstance, pThis->pszLocation); pThis->fTcpSockInPollSet = true; } LogRel(("DrvTCP: %s, %s\n", pThis->pszLocation, pThis->fIsServer ? "server" : "client")); return VINF_SUCCESS; }
int RTCString::toInt(uint32_t &i) const { if (!m_psz) return VERR_NO_DIGITS; return RTStrToUInt32Ex(m_psz, NULL, 0, &i); }
/** * Modifies the autostart database. * * @returns VBox status code. * @param fAutostart Flag whether the autostart or autostop database is modified. * @param fAddVM Flag whether a VM is added or removed from the database. */ int AutostartDb::autostartModifyDb(bool fAutostart, bool fAddVM) { int rc = VINF_SUCCESS; char *pszUser = NULL; /* Check if the path is set. */ if (!m_pszAutostartDbPath) return VERR_PATH_NOT_FOUND; rc = RTProcQueryUsernameA(RTProcSelf(), &pszUser); if (RT_SUCCESS(rc)) { char *pszFile; uint64_t fOpen = RTFILE_O_DENY_ALL | RTFILE_O_READWRITE; RTFILE hAutostartFile; AssertPtr(pszUser); if (fAddVM) fOpen |= RTFILE_O_OPEN_CREATE; else fOpen |= RTFILE_O_OPEN; rc = RTStrAPrintf(&pszFile, "%s/%s.%s", m_pszAutostartDbPath, pszUser, fAutostart ? "start" : "stop"); if (RT_SUCCESS(rc)) { rc = RTFileOpen(&hAutostartFile, pszFile, fOpen); if (RT_SUCCESS(rc)) { uint64_t cbFile; /* * Files with more than 16 bytes are rejected because they just contain * a number of the amount of VMs with autostart configured, so they * should be really really small. Anything else is bogus. */ rc = RTFileGetSize(hAutostartFile, &cbFile); if ( RT_SUCCESS(rc) && cbFile <= 16) { char abBuf[16 + 1]; /* trailing \0 */ uint32_t cAutostartVms = 0; RT_ZERO(abBuf); /* Check if the file was just created. */ if (cbFile) { rc = RTFileRead(hAutostartFile, abBuf, cbFile, NULL); if (RT_SUCCESS(rc)) { rc = RTStrToUInt32Ex(abBuf, NULL, 10 /* uBase */, &cAutostartVms); if ( rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES) rc = VINF_SUCCESS; } } if (RT_SUCCESS(rc)) { size_t cbBuf; /* Modify VM counter and write back. */ if (fAddVM) cAutostartVms++; else cAutostartVms--; if (cAutostartVms > 0) { cbBuf = RTStrPrintf(abBuf, sizeof(abBuf), "%u", cAutostartVms); rc = RTFileSetSize(hAutostartFile, cbBuf); if (RT_SUCCESS(rc)) rc = RTFileWriteAt(hAutostartFile, 0, abBuf, cbBuf, NULL); } else { /* Just delete the file if there are no VMs left. */ RTFileClose(hAutostartFile); RTFileDelete(pszFile); hAutostartFile = NIL_RTFILE; } } } else if (RT_SUCCESS(rc)) rc = VERR_FILE_TOO_BIG; if (hAutostartFile != NIL_RTFILE) RTFileClose(hAutostartFile); } RTStrFree(pszFile); } RTStrFree(pszUser); } return rc; }
/** * Tries to parse out an address at the head of the string. * * @returns true if found address, false if not. * @param psz Where to start parsing. * @param pcchAddress Where to store the address length. * @param pu64Address Where to store the address value. */ static bool TryParseAddress(const char *psz, size_t *pcchAddress, uint64_t *pu64Address) { const char *pszStart = psz; /* * Hex prefix? */ if (psz[0] == '0' && (psz[1] == 'x' || psz[1] == 'X')) psz += 2; /* * How many hex digits? We want at least 4 and at most 16. */ size_t off = 0; while (RT_C_IS_XDIGIT(psz[off])) off++; if (off < 4 || off > 16) return false; /* * Check for separator (xxxxxxxx'yyyyyyyy). */ bool fHave64bitSep = off <= 8 && psz[off] == '\'' && RT_C_IS_XDIGIT(psz[off + 1]) && RT_C_IS_XDIGIT(psz[off + 2]) && RT_C_IS_XDIGIT(psz[off + 3]) && RT_C_IS_XDIGIT(psz[off + 4]) && RT_C_IS_XDIGIT(psz[off + 5]) && RT_C_IS_XDIGIT(psz[off + 6]) && RT_C_IS_XDIGIT(psz[off + 7]) && RT_C_IS_XDIGIT(psz[off + 8]) && !RT_C_IS_XDIGIT(psz[off + 9]); if (fHave64bitSep) { uint32_t u32High; int rc = RTStrToUInt32Ex(psz, NULL, 16, &u32High); if (rc != VWRN_TRAILING_CHARS) return false; uint32_t u32Low; rc = RTStrToUInt32Ex(&psz[off + 1], NULL, 16, &u32Low); if ( rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES && rc != VWRN_TRAILING_CHARS) return false; *pu64Address = RT_MAKE_U64(u32Low, u32High); off += 1 + 8; } else { int rc = RTStrToUInt64Ex(psz, NULL, 16, pu64Address); if ( rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES && rc != VWRN_TRAILING_CHARS) return false; } *pcchAddress = psz + off - pszStart; return true; }
/** * 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) { int rcRet = 1; int rc; RTR3InitAndSUPLib(); /* * Parse input. */ if (argc <= 1) { syntax(); return 1; } bool fPowerOn = false; uint32_t u32WarpDrive = 100; /* % */ uint64_t cbMem = ~0ULL; const char *pszSavedState = NULL; const char *pszRawMem = NULL; uint64_t offRawMem = 0; const char *pszScript = NULL; for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { /* check that it's on short form */ if (argv[i][2]) { if ( strcmp(argv[i], "--help") && strcmp(argv[i], "-help")) RTPrintf("tstAnimate: Syntax error: Unknown argument '%s'.\n", argv[i]); else syntax(); return 1; } /* check for 2nd argument */ switch (argv[i][1]) { case 'r': case 'o': case 'c': case 'm': case 'w': case 'z': if (i + 1 < argc) break; RTPrintf("tstAnimate: Syntax error: '%s' takes a 2nd argument.\n", argv[i]); return 1; } /* process argument */ switch (argv[i][1]) { case 'r': pszRawMem = argv[++i]; break; case 'z': pszSavedState = argv[++i]; break; case 'o': { rc = RTStrToUInt64Ex(argv[++i], NULL, 0, &offRawMem); if (RT_FAILURE(rc)) { RTPrintf("tstAnimate: Syntax error: Invalid offset given to -o.\n"); return 1; } break; } case 'm': { char *pszNext; rc = RTStrToUInt64Ex(argv[++i], &pszNext, 0, &cbMem); if (RT_FAILURE(rc)) { RTPrintf("tstAnimate: Syntax error: Invalid memory size given to -m.\n"); return 1; } switch (*pszNext) { case 'G': cbMem *= _1G; pszNext++; break; case 'M': cbMem *= _1M; pszNext++; break; case 'K': cbMem *= _1K; pszNext++; break; case '\0': break; default: RTPrintf("tstAnimate: Syntax error: Invalid memory size given to -m.\n"); return 1; } if (*pszNext) { RTPrintf("tstAnimate: Syntax error: Invalid memory size given to -m.\n"); return 1; } break; } case 's': pszScript = argv[++i]; break; case 'p': fPowerOn = true; break; case 'w': { rc = RTStrToUInt32Ex(argv[++i], NULL, 0, &u32WarpDrive); if (RT_FAILURE(rc)) { RTPrintf("tstAnimate: Syntax error: Invalid number given to -w.\n"); return 1; } break; } case 'h': case 'H': case '?': syntax(); return 1; default: RTPrintf("tstAnimate: Syntax error: Unknown argument '%s'.\n", argv[i]); return 1; } } else { RTPrintf("tstAnimate: Syntax error at arg no. %d '%s'.\n", i, argv[i]); syntax(); return 1; } } /* * Check that the basic requirements are met. */ if (pszRawMem && pszSavedState) { RTPrintf("tstAnimate: Syntax error: Either -z or -r, not both.\n"); return 1; } if (!pszRawMem && !pszSavedState) { RTPrintf("tstAnimate: Syntax error: The -r argument is compulsory.\n"); return 1; } /* * Open the files. */ RTFILE FileRawMem = NIL_RTFILE; if (pszRawMem) { rc = RTFileOpen(&FileRawMem, pszRawMem, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); if (RT_FAILURE(rc)) { RTPrintf("tstAnimate: error: Failed to open '%s': %Rrc\n", pszRawMem, rc); return 1; } } RTFILE FileScript = NIL_RTFILE; if (pszScript) { rc = RTFileOpen(&FileScript, pszScript, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); if (RT_FAILURE(rc)) { RTPrintf("tstAnimate: error: Failed to open '%s': %Rrc\n", pszScript, rc); return 1; } } /* * Figure the memsize if not specified. */ if (cbMem == ~0ULL) { if (FileRawMem != NIL_RTFILE) { rc = RTFileGetSize(FileRawMem, &cbMem); AssertReleaseRC(rc); cbMem -= offRawMem; cbMem &= ~(PAGE_SIZE - 1); } else { RTPrintf("tstAnimate: error: too lazy to figure out the memsize in a saved state.\n"); return 1; } } RTPrintf("tstAnimate: info: cbMem=0x%llx bytes\n", cbMem); /* * Open a release log. */ static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES; PRTLOGGER pRelLogger; rc = RTLogCreate(&pRelLogger, RTLOGFLAGS_PREFIX_TIME_PROG, "all", "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, RTLOGDEST_FILE, "./tstAnimate.log"); if (RT_SUCCESS(rc)) RTLogRelSetDefaultInstance(pRelLogger); else RTPrintf("tstAnimate: rtLogCreateEx failed - %Rrc\n", rc); /* * Create empty VM. */ PVM pVM; rc = VMR3Create(1, NULL, NULL, NULL, cfgmR3CreateDefault, &cbMem, &pVM); if (RT_SUCCESS(rc)) { /* * Load memory. */ if (FileRawMem != NIL_RTFILE) rc = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)loadMem, 3, pVM, FileRawMem, &offRawMem); else rc = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)SSMR3Load, 7, pVM, pszSavedState, (uintptr_t)NULL /*pStreamOps*/, (uintptr_t)NULL /*pvUser*/, SSMAFTER_DEBUG_IT, (uintptr_t)NULL /*pfnProgress*/, (uintptr_t)NULL /*pvProgressUser*/); if (RT_SUCCESS(rc)) { /* * Load register script. */ if (FileScript != NIL_RTFILE) rc = VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)scriptRun, 2, pVM, FileScript); if (RT_SUCCESS(rc)) { if (fPowerOn) { /* * Adjust warpspeed? */ if (u32WarpDrive != 100) { rc = TMR3SetWarpDrive(pVM, u32WarpDrive); if (RT_FAILURE(rc)) RTPrintf("warning: TMVirtualSetWarpDrive(,%u) -> %Rrc\n", u32WarpDrive, rc); } /* * Start the thing with single stepping and stuff enabled. * (Try make sure we don't execute anything in raw mode.) */ RTPrintf("info: powering on the VM...\n"); RTLogGroupSettings(NULL, "+REM_DISAS.e.l.f"); rc = REMR3DisasEnableStepping(pVM, true); if (RT_SUCCESS(rc)) { rc = EMR3SetExecutionPolicy(pVM, EMEXECPOLICY_RECOMPILE_RING0, true); AssertReleaseRC(rc); rc = EMR3SetExecutionPolicy(pVM, EMEXECPOLICY_RECOMPILE_RING3, true); AssertReleaseRC(rc); DBGFR3Info(pVM, "cpumguest", "verbose", NULL); if (fPowerOn) rc = VMR3PowerOn(pVM); if (RT_SUCCESS(rc)) { RTPrintf("info: VM is running\n"); signal(SIGINT, SigInterrupt); while (!g_fSignaled) RTThreadSleep(1000); } else RTPrintf("error: Failed to power on the VM: %Rrc\n", rc); } else RTPrintf("error: Failed to enabled singlestepping: %Rrc\n", rc); } else { /* * Don't start it, just enter the debugger. */ RTPrintf("info: entering debugger...\n"); DBGFR3Info(pVM, "cpumguest", "verbose", NULL); signal(SIGINT, SigInterrupt); while (!g_fSignaled) RTThreadSleep(1000); } RTPrintf("info: shutting down the VM...\n"); } /* execScript complains */ } else if (FileRawMem == NIL_RTFILE) /* loadMem complains, SSMR3Load doesn't */ RTPrintf("tstAnimate: error: SSMR3Load failed: rc=%Rrc\n", rc); rcRet = RT_SUCCESS(rc) ? 0 : 1; /* * Cleanup. */ rc = VMR3Destroy(pVM); if (!RT_SUCCESS(rc)) { RTPrintf("tstAnimate: error: failed to destroy vm! rc=%Rrc\n", rc); rcRet++; } } else { RTPrintf("tstAnimate: fatal error: failed to create vm! rc=%Rrc\n", rc); rcRet++; } return rcRet; }
/** * Attempts to convert an ISO date string to a time structure. * * We're a little forgiving with zero padding, unspecified parts, and leading * and trailing spaces. * * @retval pTime on success, * @retval NULL on failure. * @param pTime Where to store the time on success. * @param pszString The ISO date string to convert. */ RTDECL(PRTTIME) RTTimeFromString(PRTTIME pTime, const char *pszString) { /* Ignore leading spaces. */ while (RT_C_IS_SPACE(*pszString)) pszString++; /* * Init non date & time parts. */ pTime->fFlags = RTTIME_FLAGS_TYPE_LOCAL; pTime->offUTC = 0; /* * The day part. */ /* Year */ int rc = RTStrToInt32Ex(pszString, (char **)&pszString, 10, &pTime->i32Year); if (rc != VWRN_TRAILING_CHARS) return NULL; bool const fLeapYear = rtTimeIsLeapYear(pTime->i32Year); if (fLeapYear) pTime->fFlags |= RTTIME_FLAGS_LEAP_YEAR; if (*pszString++ != '-') return NULL; /* Month of the year. */ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Month); if (rc != VWRN_TRAILING_CHARS) return NULL; if (pTime->u8Month == 0 || pTime->u8Month > 12) return NULL; if (*pszString++ != '-') return NULL; /* Day of month.*/ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8MonthDay); if (rc != VWRN_TRAILING_CHARS && rc != VINF_SUCCESS) return NULL; unsigned const cDaysInMonth = fLeapYear ? g_acDaysInMonthsLeap[pTime->u8Month - 1] : g_acDaysInMonths[pTime->u8Month - 1]; if (pTime->u8MonthDay == 0 || pTime->u8MonthDay > cDaysInMonth) return NULL; /* Calculate year day. */ pTime->u16YearDay = pTime->u8MonthDay - 1 + (fLeapYear ? g_aiDayOfYearLeap[pTime->u8Month - 1] : g_aiDayOfYear[pTime->u8Month - 1]); /* * The time part. */ if (*pszString++ != 'T') return NULL; /* Hour. */ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Hour); if (rc != VWRN_TRAILING_CHARS) return NULL; if (pTime->u8Hour > 23) return NULL; if (*pszString++ != ':') return NULL; /* Minute. */ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Minute); if (rc != VWRN_TRAILING_CHARS) return NULL; if (pTime->u8Minute > 59) return NULL; if (*pszString++ != ':') return NULL; /* Second. */ rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Minute); if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES) return NULL; if (pTime->u8Second > 59) return NULL; /* Nanoseconds is optional and probably non-standard. */ if (*pszString == '.') { rc = RTStrToUInt32Ex(pszString + 1, (char **)&pszString, 10, &pTime->u32Nanosecond); if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES) return NULL; if (pTime->u32Nanosecond >= 1000000000) return NULL; } else pTime->u32Nanosecond = 0; /* * Time zone. */ if (*pszString == 'Z') { pszString++; pTime->fFlags &= ~RTTIME_FLAGS_TYPE_MASK; pTime->fFlags |= ~RTTIME_FLAGS_TYPE_UTC; pTime->offUTC = 0; } else if ( *pszString == '+' || *pszString == '-') { rc = RTStrToInt32Ex(pszString, (char **)&pszString, 10, &pTime->offUTC); if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES) return NULL; } /* else: No time zone given, local with offUTC = 0. */ /* * The rest of the string should be blanks. */ char ch; while ((ch = *pszString++) != '\0') if (!RT_C_IS_BLANK(ch)) return NULL; return pTime; }
RTDECL(int) RTGetOpt(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion) { /* * Reset the variables kept in state. */ pState->pDef = NULL; pState->uIndex = UINT32_MAX; /* * Make sure the union is completely cleared out, whatever happens below. */ pValueUnion->u64 = 0; pValueUnion->pDef = NULL; /* * The next option. */ bool fShort; int iThis; const char *pszArgThis; PCRTGETOPTDEF pOpt; if (pState->pszNextShort) { /* * We've got short options left over from the previous call. */ pOpt = rtGetOptSearchShort(*pState->pszNextShort, pState->paOptions, pState->cOptions, pState->fFlags); if (!pOpt) { pValueUnion->psz = pState->pszNextShort; return VERR_GETOPT_UNKNOWN_OPTION; } pState->pszNextShort++; pszArgThis = pState->pszNextShort - 2; iThis = pState->iNext; fShort = true; } else { /* * Pop off the next argument. Sorting options and dealing with the * dash-dash makes this a little extra complicated. */ for (;;) { if (pState->iNext >= pState->argc) return 0; if (pState->cNonOptions) { if (pState->cNonOptions == INT32_MAX) { pValueUnion->psz = pState->argv[pState->iNext++]; return VINF_GETOPT_NOT_OPTION; } if (pState->iNext + pState->cNonOptions >= pState->argc) { pState->cNonOptions = INT32_MAX; continue; } } iThis = pState->iNext++; pszArgThis = pState->argv[iThis + pState->cNonOptions]; /* * Do a long option search first and then a short option one. * This way we can make sure single dash long options doesn't * get mixed up with short ones. */ pOpt = rtGetOptSearchLong(pszArgThis, pState->paOptions, pState->cOptions, pState->fFlags); if ( !pOpt && pszArgThis[0] == '-' && pszArgThis[1] != '-' && pszArgThis[1] != '\0') { pOpt = rtGetOptSearchShort(pszArgThis[1], pState->paOptions, pState->cOptions, pState->fFlags); fShort = pOpt != NULL; } else fShort = false; /* Look for dash-dash. */ if (!pOpt && !strcmp(pszArgThis, "--")) { rtGetOptMoveArgvEntries(&pState->argv[iThis], &pState->argv[iThis + pState->cNonOptions]); pState->cNonOptions = INT32_MAX; continue; } /* Options first hacks. */ if (pState->fFlags & RTGETOPTINIT_FLAGS_OPTS_FIRST) { if (pOpt) rtGetOptMoveArgvEntries(&pState->argv[iThis], &pState->argv[iThis + pState->cNonOptions]); else if (*pszArgThis == '-') { pValueUnion->psz = pszArgThis; return VERR_GETOPT_UNKNOWN_OPTION; } else { /* not an option, add it to the non-options and try again. */ pState->iNext--; pState->cNonOptions++; /* Switch to returning non-options if we've reached the end. */ if (pState->iNext + pState->cNonOptions >= pState->argc) pState->cNonOptions = INT32_MAX; continue; } } /* done */ break; } } if (pOpt) { pValueUnion->pDef = pOpt; /* in case of no value or error. */ if ((pOpt->fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING) { /* * Find the argument value. * * A value is required with the argument. We're trying to be * understanding here and will permit any of the following: * -svalue, -s value, -s:value and -s=value * (Ditto for long options.) */ const char *pszValue; if (fShort) { if (pszArgThis[2] == '\0') { if (iThis + 1 >= pState->argc) return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING; pszValue = pState->argv[iThis + pState->cNonOptions + 1]; rtGetOptMoveArgvEntries(&pState->argv[iThis + 1], &pState->argv[iThis + pState->cNonOptions + 1]); pState->iNext++; } else /* same argument. */ pszValue = &pszArgThis[2 + (pszArgThis[2] == ':' || pszArgThis[2] == '=')]; if (pState->pszNextShort) { pState->pszNextShort = NULL; pState->iNext++; } } else { size_t cchLong = strlen(pOpt->pszLong); if (pOpt->fFlags & RTGETOPT_FLAG_INDEX) { if (pszArgThis[cchLong] == '\0') return VERR_GETOPT_INDEX_MISSING; uint32_t uIndex; char *pszRet = NULL; int rc = RTStrToUInt32Ex(&pszArgThis[cchLong], &pszRet, 10, &uIndex); if (rc == VWRN_TRAILING_CHARS) { if ( pszRet[0] != ':' && pszRet[0] != '=') return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pState->uIndex = uIndex; pszValue = pszRet + 1; } else if (rc == VINF_SUCCESS) { if (iThis + 1 >= pState->argc) return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING; pState->uIndex = uIndex; pszValue = pState->argv[iThis + pState->cNonOptions + 1]; rtGetOptMoveArgvEntries(&pState->argv[iThis + 1], &pState->argv[iThis + pState->cNonOptions + 1]); pState->iNext++; } else AssertMsgFailedReturn(("%s\n", pszArgThis), VERR_GETOPT_INVALID_ARGUMENT_FORMAT); /* search bug */ } else { if (pszArgThis[cchLong] == '\0') { if (iThis + 1 >= pState->argc) return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING; pszValue = pState->argv[iThis + pState->cNonOptions + 1]; rtGetOptMoveArgvEntries(&pState->argv[iThis + 1], &pState->argv[iThis + pState->cNonOptions + 1]); pState->iNext++; } else /* same argument. */ pszValue = &pszArgThis[cchLong + 1]; } } /* * Set up the ValueUnion. */ int rc = rtGetOptProcessValue(pOpt->fFlags, pszValue, pValueUnion); if (RT_FAILURE(rc)) return rc; } else if (fShort) { /* * Deal with "compressed" short option lists, correcting the next * state variables for the start and end cases. */ if (pszArgThis[2]) { if (!pState->pszNextShort) { /* start */ pState->pszNextShort = &pszArgThis[2]; pState->iNext--; } } else if (pState->pszNextShort) { /* end */ pState->pszNextShort = NULL; pState->iNext++; } } else if (pOpt->fFlags & RTGETOPT_FLAG_INDEX) { size_t cchLong = strlen(pOpt->pszLong); if (pszArgThis[cchLong] == '\0') return VERR_GETOPT_INDEX_MISSING; uint32_t uIndex; if (RTStrToUInt32Full(&pszArgThis[cchLong], 10, &uIndex) == VINF_SUCCESS) pState->uIndex = uIndex; else AssertMsgFailedReturn(("%s\n", pszArgThis), VERR_GETOPT_INVALID_ARGUMENT_FORMAT); /* search bug */ } pState->pDef = pOpt; return pOpt->iShort; } /* * Not a known option argument. If it starts with a switch char (-) we'll * fail with unknown option, and if it doesn't we'll return it as a non-option. */ if (*pszArgThis == '-') { pValueUnion->psz = pszArgThis; return VERR_GETOPT_UNKNOWN_OPTION; } pValueUnion->psz = pszArgThis; return VINF_GETOPT_NOT_OPTION; }
/** * Parses any string and tests if it is an IPv6 Address * * This function should NOT be used directly. If you do, note * that no security checks are done at the moment. This can change. * * @returns iprt sstatus code. * @param pszAddress The strin that holds the IPv6 address * @param addressLength The length of pszAddress * @param pszAddressOut Returns a plain, full blown IPv6 address * as a char array * @param addressOutSize The size of pszAddressOut (length) * @param pPortOut 32 bit unsigned integer, holding the port * If pszAddress doesn't contain a port, it's 0 * @param pszScopeOut Returns the scope of the address, if none it's 0 * @param scopeOutSize sizeof(pszScopeOut) * @param pBrackets returns true if the address was enclosed in brackets * @param pEmbeddedV4 returns true if the address is an embedded IPv4 address * @param followRfc if set to true, the function follows RFC (default) */ static int rtStrParseAddrStr6(const char *pszAddress, size_t addressLength, char *pszAddressOut, size_t addressOutSize, uint32_t *pPortOut, char *pszIfIdOut, size_t ifIdOutSize, bool *pBrackets, bool *pEmbeddedV4, bool followRfc) { /************************\ * Pointer Hell Ahead * \************************/ const char szIpV6AddressChars[] = "ABCDEF01234567890abcdef.:[]%"; // order IMPORTANT const char szIpV4AddressChars[] = "01234567890.:[]"; // order IMPORTANT const char szLinkLocalPrefix[] = "FfEe8800"; // const char *pszIpV6AddressChars = NULL, *pszIpV4AddressChars = NULL, *pszLinkLocalPrefix = NULL; char *pszSourceAddress = NULL, *pszSourceAddressStart = NULL; char *pszResultAddress = NULL, *pszResultAddressStart = NULL; char *pszResultAddress4 = NULL, *pszResultAddress4Start = NULL; char *pszResultPort = NULL, *pszResultPortStart = NULL; char *pszInternalAddress = NULL, *pszInternalAddressStart = NULL; char *pszInternalPort = NULL, *pszInternalPortStart = NULL; char *pStart = NULL, *pNow = NULL, *pNext = NULL, *pNowChar = NULL, *pIfId = NULL, *pIfIdEnd = NULL; char *pNowDigit = NULL, *pFrom = NULL, *pTo = NULL, *pLast = NULL; char *pGap = NULL, *pMisc = NULL, *pDotStart = NULL, *pFieldStart = NULL, *pFieldEnd = NULL; char *pFieldStartLongest = NULL, *pBracketOpen = NULL, *pBracketClose = NULL; char *pszRc = NULL; bool isLinkLocal = false; char szDummy[4]; uint8_t *pByte = NULL; uint32_t byteOut = 0; uint16_t returnValue = 0; uint32_t colons = 0; uint32_t colonsOverAll = 0; uint32_t fieldLength = 0; uint32_t dots = 0; size_t gapSize = 0; uint32_t intPortOut = 0; pszIpV4AddressChars = &szIpV4AddressChars[0]; pszIpV6AddressChars = &szIpV6AddressChars[6]; pszLinkLocalPrefix = &szLinkLocalPrefix[6]; if (!followRfc) pszIpV6AddressChars = &szIpV6AddressChars[0]; if (addressLength<2) returnValue = 711; pszResultAddressStart = (char *)RTMemTmpAlloc(34); pszInternalAddressStart = (char *)RTMemTmpAlloc(34); pszInternalPortStart = (char * )RTMemTmpAlloc(10); if (! (pszResultAddressStart && pszInternalAddressStart && pszInternalPortStart)) { if (pszResultAddressStart) RTMemTmpFree(pszResultAddressStart); if (pszInternalAddressStart) RTMemTmpFree(pszInternalAddressStart); if (pszInternalPortStart) RTMemTmpFree(pszInternalPortStart); return -701; } memset(szDummy, '\0', 4); pszResultAddress = pszResultAddressStart; memset(pszResultAddressStart, '\0', 34); pszInternalAddress = pszInternalAddressStart; memset(pszInternalAddressStart, '\0' , 34); pszInternalPort = pszInternalPortStart; memset(pszInternalPortStart, '\0', 10); pszSourceAddress = pszSourceAddressStart = (char *)pszAddress; pFrom = pTo = pStart = pLast = pszSourceAddressStart; while (*pszSourceAddress != '\0' && !returnValue) { pNow = NULL; pNext = NULL; pNowChar = NULL; pNowDigit = NULL; pNow = pszSourceAddress; pNext = pszSourceAddress + 1; if (!pFrom) pFrom = pTo = pNow; pNowChar = (char *)memchr(pszIpV6AddressChars, *pNow, strlen(pszIpV6AddressChars)); pNowDigit = (char *)memchr(pszIpV6AddressChars, *pNow, strlen(pszIpV6AddressChars) - 5); if (pszResultPort) { if (pLast && (pszResultPort == pszSourceAddressStart)) { if (*pLast == '\0') returnValue = 721; pszResultPortStart = (char *)RTMemTmpAlloc(10); if (!pszResultPortStart) returnValue = 702; memset(pszResultPortStart, '\0', 10); pszResultPort = pszResultPortStart; pszSourceAddress = pLast; pMisc = pLast; pLast = NULL; continue; } pNowDigit = NULL; pNowDigit = (char *)memchr(pszIpV4AddressChars, *pNow, strlen(pszIpV4AddressChars) - 4); if (strlen(pszResultPortStart) == 5) returnValue = 11; if (*pNow == '0' && pszResultPort == pszResultPortStart && *pNext != '\0' && (pNow - pMisc) < 5 ) { pszSourceAddress++; continue; } if (pNowDigit) { *pszResultPort = *pNowDigit; pszResultPort++; pszSourceAddress++; continue; } else returnValue = 12; } if (pszResultAddress4) { if (pszResultAddress4 == pszSourceAddressStart && pLast) { dots = 0; pszResultAddress4 = NULL; pszResultAddress4Start = NULL; pszResultAddress4Start = (char *)RTMemTmpAlloc(20); if (!pszResultAddress4Start) { returnValue = 401; break; } memset(pszResultAddress4Start, '\0', 20); pszResultAddress4 = pszResultAddress4Start; pszSourceAddress = pLast; pFrom = pLast; pTo = pLast; pLast = NULL; continue; } pTo = pNow; pNowDigit = NULL; pNowDigit = (char *)memchr(pszIpV4AddressChars, *pNow, strlen(pszIpV4AddressChars) - 4); if (!pNowDigit && *pNow != '.' && *pNow != ']' && *pNow != ':' && *pNow != '%') returnValue = 412; if ((pNow - pFrom) > 3) { returnValue = 402; break; } if (pNowDigit && *pNext != '\0') { pszSourceAddress++; continue; } if (!pNowDigit && !pBracketOpen && (*pNext == '.' || *pNext == ']' || *pNext == ':')) returnValue = 411; memset(pszResultAddress4, '0', 3); pMisc = pszResultAddress4 + 2; pszResultAddress4 = pszResultAddress4 + 3; if (*pNow != '.' && !pNowDigit && strlen(pszResultAddress4Start) < 9) returnValue = 403; if ((pTo - pFrom) > 0) pTo--; dots++; while (pTo >= pFrom) { *pMisc = *pTo; pMisc--; pTo--; } if (dots == 4 && *pNow == '.') { if (!pBracketOpen) { pszResultPort = pszSourceAddressStart; pLast = pNext; } else { returnValue = 409; } } dots = 0; pFrom = pNext; pTo = pNext; if (strlen(pszResultAddress4Start) > 11) pszResultAddress4 = NULL; if ((*pNow == ':' || *pNow == '.') && strlen(pszResultAddress4Start) == 12) { pLast = pNext; pszResultPort = pszSourceAddressStart; } if (*pNow == '%') { pIfId = pNow; pLast = pNow; continue; } pszSourceAddress = pNext; if (*pNow != ']') continue; pFrom = pNow; pTo = pNow; } if (pIfId && (!pIfIdEnd)) { if (*pIfId == '%' && pIfId == pLast && *pNext != '\0') { pFrom = pNext; pIfId = pNext; pLast = NULL; pszSourceAddress++; continue; } if (*pNow == '%' && pIfId <= pNow) { returnValue = 442; break; } if (*pNow != ']' && *pNext != '\0') { pTo = pNow; pszSourceAddress++; continue; } if (*pNow == ']') { pIfIdEnd = pNow - 1; pFrom = pNow; pTo = pNow; continue; } else { pIfIdEnd = pNow; pFrom = NULL; pTo = NULL; pszSourceAddress++; continue; } } if (!pNowChar) { returnValue = 254; if (followRfc) { pMisc = (char *)memchr(&szIpV6AddressChars[0], *pNow, strlen(&szIpV6AddressChars[0])); if (pMisc) returnValue = 253; } } if (strlen(pszResultAddressStart) > 32 && !pszResultAddress4Start) returnValue = 255; if (pNowDigit && *pNext != '\0' && colons == 0) { pTo = pNow; pszSourceAddress++; continue; } if (*pNow == ':' && *pNext != '\0') { colonsOverAll++; colons++; pszSourceAddress++; continue; } if (*pNow == ':' ) { colons++; colonsOverAll++; } if (*pNow == '.') { pMisc = pNow; while (*pMisc != '\0' && *pMisc != ']') { if (*pMisc == '.') dots++; pMisc++; } } if (*pNow == ']') { if (pBracketClose) returnValue = 77; if (!pBracketOpen) returnValue = 22; if (*pNext == ':' || *pNext == '.') { pszResultPort = pszSourceAddressStart; pLast = pNext + 1; } if (pFrom == pNow) pFrom = NULL; pBracketClose = pNow; } if (*pNow == '[') { if (pBracketOpen) returnValue = 23; if (pStart != pNow) returnValue = 24; pBracketOpen = pNow; pStart++; pFrom++; pszSourceAddress++; continue; } if (*pNow == '%') { if (pIfId) returnValue = 441; pLast = pNext; pIfId = pNext; } if (colons > 0) { if (colons == 1) { if (pStart + 1 == pNow ) returnValue = 31; if (*pNext == '\0' && !pNowDigit) returnValue = 32; pLast = pNow; } if (colons == 2) { if (pGap) returnValue = 33; pGap = pszResultAddress + 4; if (pStart + 1 == pNow || pStart + 2 == pNow) { pGap = pszResultAddressStart; pFrom = pNow; } if (*pNext == '\0' && !pNowDigit) pszSourceAddress++; if (*pNext != ':' && *pNext != '.') pLast = pNow; } if (colons == 3) { pFrom = pLast; pLast = pNow; if (*pNext == '\0' && !pNowDigit) returnValue = 34; if (pBracketOpen) returnValue = 35; if (pGap && followRfc) returnValue = 36; if (!pGap) pGap = pszResultAddress + 4; if (pStart + 3 == pNow) { pszResultPort = pszSourceAddressStart; pGap = pszResultAddress; pFrom = NULL; } if (pNowDigit) { pszResultPort = pszSourceAddressStart; } } } if (*pNext == '\0' && colons == 0 && !pIfIdEnd) { pFrom = pLast; if (pNowDigit) pTo = pNow; pLast = NULL; } if (dots > 0) { if (dots == 1) { pszResultPort = pszSourceAddressStart; pLast = pNext; } if (dots == 4 && pBracketOpen) returnValue = 601; if (dots == 3 || dots == 4) { pszResultAddress4 = pszSourceAddressStart; pLast = pFrom; pFrom = NULL; } if (dots > 4) returnValue = 603; dots = 0; } if (pFrom && pTo) { if (pTo - pFrom > 3) { returnValue = 51; break; } if (followRfc) { if ((pTo - pFrom > 0) && *pFrom == '0') returnValue = 101; if ((pTo - pFrom) == 0 && *pFrom == '0' && colons == 2) returnValue = 102; if ((pTo - pFrom) == 0 && *pFrom == '0' && pszResultAddress == pGap) returnValue = 103; if ((pTo - pFrom) == 0 && *pFrom == '0') { if (!pFieldStart) { pFieldStart = pszResultAddress; pFieldEnd = pszResultAddress + 4; } else { pFieldEnd = pFieldEnd + 4; } } else { if ((size_t)(pFieldEnd - pFieldStart) > fieldLength) { fieldLength = pFieldEnd - pFieldStart; pFieldStartLongest = pFieldStart; } pFieldStart = NULL; pFieldEnd = NULL; } } if (!(pGap == pszResultAddressStart && (size_t)(pNow - pStart) == colons)) { memset(pszResultAddress, '0', 4); pMisc = pszResultAddress + 3; pszResultAddress = pszResultAddress + 4; if (pFrom == pStart && (pTo - pFrom) == 3) { isLinkLocal = true; while (pTo >= pFrom) { *pMisc = *pTo; if (*pTo != *pszLinkLocalPrefix && *pTo != *(pszLinkLocalPrefix + 1)) isLinkLocal = false; pTo--; pMisc--; pszLinkLocalPrefix = pszLinkLocalPrefix - 2; } } else { while (pTo >= pFrom) { *pMisc = *pTo; pMisc--; pTo--; } } } pFrom = pNow; pTo = pNow; } if (*pNext == '\0' && colons == 0) pszSourceAddress++; if (*pNext == '\0' && !pBracketClose && !pszResultPort) pTo = pNext; colons = 0; } // end of loop if (!returnValue && colonsOverAll < 2) returnValue = 252; if (!returnValue && (pBracketOpen && !pBracketClose)) returnValue = 25; if (!returnValue && pGap) { gapSize = 32 - strlen(pszResultAddressStart); if (followRfc) { if (gapSize < 5) returnValue = 104; if (fieldLength > gapSize) returnValue = 105; if (fieldLength == gapSize && pFieldStartLongest < pGap) returnValue = 106; } pszResultAddress = pszResultAddressStart; pszInternalAddress = pszInternalAddressStart; if (!returnValue && pszResultAddress4Start) { if (strlen(pszResultAddressStart) > 4) returnValue = 405; pszResultAddress = pszResultAddressStart; if (pGap != pszResultAddressStart) returnValue = 407; memset(pszInternalAddressStart, '0', 20); pszInternalAddress = pszInternalAddressStart + 20; for (int i = 0; i < 4; i++) { if (*pszResultAddress != 'f' && *pszResultAddress != 'F') { returnValue = 406; break; } *pszInternalAddress = *pszResultAddress; pszResultAddress++; pszInternalAddress++; } pszResultAddress4 = pszResultAddress4Start; for (int i = 0; i<4; i++) { memcpy(szDummy, pszResultAddress4, 3); int rc = RTStrToUInt32Ex((const char *)&szDummy[0], NULL, 16, &byteOut); if (rc == 0 && byteOut < 256) { RTStrPrintf(szDummy, 3, "%02x", byteOut); memcpy(pszInternalAddress, szDummy, 2); pszInternalAddress = pszInternalAddress + 2; pszResultAddress4 = pszResultAddress4 + 3; memset(szDummy, '\0', 4); } else { returnValue = 499; } } } else { while (!returnValue && pszResultAddress != pGap) { *pszInternalAddress = *pszResultAddress; pszResultAddress++; pszInternalAddress++; } memset(pszInternalAddress, '0', gapSize); pszInternalAddress = pszInternalAddress + gapSize; while (!returnValue && *pszResultAddress != '\0') { *pszInternalAddress = *pszResultAddress; pszResultAddress++; pszInternalAddress++; } } } else { if (!returnValue) { if (strlen(pszResultAddressStart) != 32) returnValue = 111; if (followRfc) { if (fieldLength > 4) returnValue = 112; } memcpy(pszInternalAddressStart, pszResultAddressStart, strlen(pszResultAddressStart)); } } if (pszResultPortStart) { if (strlen(pszResultPortStart) > 0 && strlen(pszResultPortStart) < 6) { memcpy(pszInternalPortStart, pszResultPortStart, strlen(pszResultPortStart)); intPortOut = 0; int rc = RTStrToUInt32Ex(pszInternalPortStart, NULL, 10, &intPortOut); if (rc == 0) { if (!(intPortOut > 0 && intPortOut < 65536)) intPortOut = 0; } else { returnValue = 888; } } else { returnValue = 889; } } /* full blown address 32 bytes, no colons -> pszInternalAddressStart port as string -> pszResultPortStart port as binary integer -> intPortOut interface id in pIfId and pIfIdEnd Now fill the out parameters. */ if (!returnValue && pszAddressOut) { if (strlen(pszInternalAddressStart) < addressOutSize) { pszRc = NULL; pszRc = (char *)memset(pszAddressOut, '\0', addressOutSize); if (!pszRc) returnValue = 910; pszRc = NULL; pszRc = (char *)memcpy(pszAddressOut, pszInternalAddressStart, strlen(pszInternalAddressStart)); if (!pszRc) returnValue = 911; } else { returnValue = 912; } } if (!returnValue && pPortOut) { *pPortOut = intPortOut; } if (!returnValue && pszIfIdOut) { if (pIfIdEnd && pIfId) { if ((size_t)(pIfIdEnd - pIfId) + 1 < ifIdOutSize) { pszRc = NULL; pszRc = (char *)memset(pszIfIdOut, '\0', ifIdOutSize); if (!pszRc) returnValue = 913; pszRc = NULL; pszRc = (char *)memcpy(pszIfIdOut, pIfId, (pIfIdEnd - pIfId) + 1); if (!pszRc) returnValue = 914; } else { returnValue = 915; } } else { pszRc = NULL; pszRc = (char *)memset(pszIfIdOut, '\0', ifIdOutSize); if (!pszRc) returnValue = 916; } // temporary hack if (isLinkLocal && (strlen(pszIfIdOut) < 1)) { memset(pszIfIdOut, '\0', ifIdOutSize); *pszIfIdOut = '%'; pszIfIdOut++; *pszIfIdOut = '0'; pszIfIdOut++; } } if (pBracketOpen && pBracketClose && pBrackets) *pBrackets = true; if (pEmbeddedV4 && pszResultAddress4Start) *pEmbeddedV4 = true; if (pszResultAddressStart) RTMemTmpFree(pszResultAddressStart); if (pszResultPortStart) RTMemTmpFree(pszResultPortStart); if (pszResultAddress4Start) RTMemTmpFree(pszResultAddress4Start); if (pszInternalAddressStart) RTMemTmpFree(pszInternalAddressStart); if (pszInternalPortStart) RTMemTmpFree(pszInternalPortStart); return (uint32_t)(returnValue - (returnValue * 2)); // make it negative... }
int DHCPServer::addOption(settings::DhcpOptionMap &aMap, DhcpOpt_T aOption, const com::Utf8Str &aValue) { settings::DhcpOptValue OptValue; if (aOption != 0) { OptValue = settings::DhcpOptValue(aValue, DhcpOptEncoding_Legacy); } /* * This is a kludge to sneak in option encoding information * through existing API. We use option 0 and supply the real * option/value in the same format that encodeOption() above * produces for getter methods. */ else { uint8_t u8Code; uint32_t u32Enc; char *pszNext; int rc; rc = RTStrToUInt8Ex(aValue.c_str(), &pszNext, 10, &u8Code); if (!RT_SUCCESS(rc)) return VERR_PARSE_ERROR; switch (*pszNext) { case ':': /* support legacy format too */ { u32Enc = DhcpOptEncoding_Legacy; break; } case '=': { u32Enc = DhcpOptEncoding_Hex; break; } case '@': { rc = RTStrToUInt32Ex(pszNext + 1, &pszNext, 10, &u32Enc); if (!RT_SUCCESS(rc)) return VERR_PARSE_ERROR; if (*pszNext != '=') return VERR_PARSE_ERROR; break; } default: return VERR_PARSE_ERROR; } aOption = (DhcpOpt_T)u8Code; OptValue = settings::DhcpOptValue(pszNext + 1, (DhcpOptEncoding_T)u32Enc); } aMap[aOption] = OptValue; return VINF_SUCCESS; }