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);
}
示例#2
0
/**
 * 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;
}
示例#3
0
/**
 * 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;
}
示例#4
0
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;
}
示例#5
0
/** 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;
}
示例#7
0
/**
 * 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;
}
示例#8
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;
}
示例#15
0
/**
 * 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;
}
示例#18
0
文件: time.cpp 项目: miguelinux/vbox
/**
 * 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;
}
示例#19
0
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;
}
示例#20
0
/**
 * 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...
}
示例#21
0
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;
}