VirtualBox

Changeset 55588 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
May 1, 2015 7:37:46 PM (10 years ago)
Author:
vboxsync
Message:

Main: Environment cleanup in the guest control area. The GuestEnvironment class implementation has been replaced by one based on IPRT's RTEnv API and it has been changed into a way of recording environment changes, thus renamed to GuestEnvironmentChanges.

Location:
trunk/src/VBox/Main
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h

    r55535 r55588  
    66
    77/*
    8  * Copyright (C) 2011-2013 Oracle Corporation
     8 * Copyright (C) 2011-2015 Oracle Corporation
    99 *
    1010 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2121
    2222#include "ConsoleImpl.h"
     23#include "Global.h"
    2324
    2425#include <iprt/asm.h>
     26#include <iprt/env.h>
    2527#include <iprt/semaphore.h>
    2628
     
    6062
    6163
    62 typedef std::vector <Utf8Str> GuestEnvironmentArray;
    63 class GuestEnvironment
    64 {
    65 public:
    66 
    67     int BuildEnvironmentBlock(void **ppvEnv, size_t *pcbEnv, uint32_t *pcEnvVars);
    68 
    69     void Clear(void);
    70 
    71     int CopyFrom(const GuestEnvironmentArray &environment);
    72 
    73     int CopyTo(GuestEnvironmentArray &environment);
    74 
    75     static void FreeEnvironmentBlock(void *pvEnv);
    76 
    77     Utf8Str Get(const Utf8Str &strKey);
    78 
    79     Utf8Str Get(size_t nPos);
    80 
    81     bool Has(const Utf8Str &strKey);
    82 
    83     int Set(const Utf8Str &strKey, const Utf8Str &strValue);
    84 
    85     int Set(const Utf8Str &strPair);
    86 
    87     size_t Size(void);
    88 
    89     int Unset(const Utf8Str &strKey);
    90 
    91 public:
    92 
    93     GuestEnvironment& operator=(const GuestEnvironmentArray &that);
    94 
    95     GuestEnvironment& operator=(const GuestEnvironment &that);
    96 
    97 protected:
    98 
    99     int appendToEnvBlock(const char *pszEnv, void **ppvList, size_t *pcbList, uint32_t *pcEnvVars);
    100 
    101 protected:
    102 
    103     std::map <Utf8Str, Utf8Str> mEnvironment;
     64
     65/**
     66 * Wrapper around the RTEnv API, unusable base class.
     67 *
     68 * @remarks Feel free to elevate this class to iprt/cpp/env.h as RTCEnv.
     69 */
     70class GuestEnvironmentBase
     71{
     72public:
     73    /**
     74     * Default constructor.
     75     *
     76     * The user must invoke one of the init methods before using the object.
     77     */
     78    GuestEnvironmentBase(void)
     79        : m_hEnv(NIL_RTENV)
     80    { }
     81
     82    /**
     83     * Destructor.
     84     */
     85    virtual ~GuestEnvironmentBase(void)
     86    {
     87        int rc = RTEnvDestroy(m_hEnv); AssertRC(rc);
     88        m_hEnv = NIL_RTENV;
     89    }
     90
     91    /**
     92     * Initialize this as a normal environment block.
     93     * @returns IPRT status code.
     94     */
     95    int initNormal(void)
     96    {
     97        AssertReturn(m_hEnv == NIL_RTENV, VERR_WRONG_ORDER);
     98        return RTEnvCreate(&m_hEnv);
     99    }
     100
     101    /**
     102     * Returns the variable count.
     103     * @return Number of variables.
     104     * @sa      RTEnvCountEx
     105     */
     106    uint32_t count(void) const
     107    {
     108        return RTEnvCountEx(m_hEnv);
     109    }
     110
     111    /**
     112     * Deletes the environment change record entirely.
     113     *
     114     * The count() method will return zero after this call.
     115     *
     116     * @sa      RTEnvReset
     117     */
     118    void reset(void)
     119    {
     120        int rc = RTEnvReset(m_hEnv);
     121        AssertRC(rc);
     122    }
     123
     124    /**
     125     * Exports the environment change block as an array of putenv style strings.
     126     *
     127     *
     128     * @returns VINF_SUCCESS or VERR_NO_MEMORY.
     129     * @param   pArray              The output array.
     130     */
     131    int queryPutEnvArray(std::vector<com::Utf8Str> *pArray) const
     132    {
     133        uint32_t cVars = RTEnvCountEx(m_hEnv);
     134        try
     135        {
     136            pArray->resize(cVars);
     137            for (uint32_t iVar = 0; iVar < cVars; iVar++)
     138            {
     139                const char *psz = RTEnvGetByIndexRawEx(m_hEnv, iVar);
     140                AssertReturn(psz, VERR_INTERNAL_ERROR_3); /* someone is racing us! */
     141                (*pArray)[iVar] = psz;
     142            }
     143            return VINF_SUCCESS;
     144        }
     145        catch (std::bad_alloc &)
     146        {
     147            return VERR_NO_MEMORY;
     148        }
     149    }
     150
     151    /**
     152     * Applies an array of putenv style strings.
     153     *
     154     * @returns IPRT status code.
     155     * @param   rArray              The array with the putenv style strings.
     156     * @sa      RTEnvPutEnvEx
     157     */
     158    int applyPutEnvArray(const std::vector<com::Utf8Str> &rArray)
     159    {
     160        size_t cArray = rArray.size();
     161        for (size_t i = 0; i < cArray; i++)
     162        {
     163            int rc = RTEnvPutEx(m_hEnv, rArray[i].c_str());
     164            if (RT_FAILURE(rc))
     165                return rc;
     166        }
     167        return VINF_SUCCESS;
     168    }
     169
     170    /**
     171     * See RTEnvQueryUtf8Block for details.
     172     * @returns IPRT status code.
     173     * @param   ppszzBlock      Where to return the block pointer.
     174     * @param   pcbBlock        Where to optionally return the block size.
     175     * @sa      RTEnvQueryUtf8Block
     176     */
     177    int queryUtf8Block(char **ppszzBlock, size_t *pcbBlock)
     178    {
     179        return RTEnvQueryUtf8Block(m_hEnv, true /*fSorted*/, ppszzBlock, pcbBlock);
     180    }
     181
     182    /**
     183     * Frees what queryUtf8Block returned, NULL ignored.
     184     * @sa      RTEnvFreeUtf8Block
     185     */
     186    static void freeUtf8Block(char *pszzBlock)
     187    {
     188        return RTEnvFreeUtf8Block(pszzBlock);
     189    }
     190
     191    /**
     192     * Get an environment variable.
     193     *
     194     * @returns IPRT status code.
     195     * @param   rName               The variable name.
     196     * @param   pValue              Where to return the value.
     197     * @sa      RTEnvGetEx
     198     */
     199    int getVariable(const com::Utf8Str &rName, com::Utf8Str *pValue) const
     200    {
     201        size_t cchNeeded;
     202        int rc = RTEnvGetEx(m_hEnv, rName.c_str(), NULL, 0, &cchNeeded);
     203        if (   RT_SUCCESS(rc)
     204            || rc == VERR_BUFFER_OVERFLOW)
     205        {
     206            try
     207            {
     208                pValue->reserve(cchNeeded + 1);
     209                rc = RTEnvGetEx(m_hEnv, rName.c_str(), pValue->mutableRaw(), pValue->capacity(), NULL);
     210                pValue->jolt();
     211            }
     212            catch (std::bad_alloc &)
     213            {
     214                rc = VERR_NO_STR_MEMORY;
     215            }
     216        }
     217        return rc;
     218    }
     219
     220    /**
     221     * Set an environment variable.
     222     *
     223     * @returns IPRT status code.
     224     * @param   rName               The variable name.
     225     * @param   rValue              The value of the variable.
     226     * @sa      RTEnvSetEx
     227     */
     228    int setVariable(const com::Utf8Str &rName, const com::Utf8Str &rValue)
     229    {
     230        return RTEnvSetEx(m_hEnv, rName.c_str(), rValue.c_str());
     231    }
     232
     233    /**
     234     * Unset an environment variable.
     235     *
     236     * @returns IPRT status code.
     237     * @param   rName               The variable name.
     238     * @sa      RTEnvUnsetEx
     239     */
     240    int unsetVariable(const com::Utf8Str &rName)
     241    {
     242        return RTEnvUnsetEx(m_hEnv, rName.c_str());
     243    }
     244
     245#if 0
     246private:
     247    /* No copy operator. */
     248    GuestEnvironmentBase(const GuestEnvironmentBase &) { throw E_FAIL; }
     249#else
     250    /**
     251     * Copy constructor.
     252     * @throws HRESULT
     253     */
     254    GuestEnvironmentBase(const GuestEnvironmentBase &rThat, bool fChangeRecord)
     255        : m_hEnv(NIL_RTENV)
     256    {
     257        int rc = cloneCommon(rThat, fChangeRecord);
     258        if (RT_FAILURE(rc))
     259            throw (Global::vboxStatusCodeToCOM(rc));
     260    }
     261#endif
     262
     263protected:
     264    /**
     265     * Common clone/copy method with type conversion abilities.
     266     *
     267     * @returns IPRT status code.
     268     * @param   rThat           The object to clone.
     269     * @param   fChangeRecord   Whether the this instance is a change record (true)
     270     *                          or normal (false) environment.
     271     */
     272    int cloneCommon(const GuestEnvironmentBase &rThat, bool fChangeRecord)
     273    {
     274        int   rc = VINF_SUCCESS;
     275        RTENV hNewEnv = NIL_RTENV;
     276        if (rThat.m_hEnv != NIL_RTENV)
     277        {
     278            if (RTEnvIsChangeRecord(rThat.m_hEnv) == fChangeRecord)
     279                rc = RTEnvClone(&hNewEnv, rThat.m_hEnv);
     280            else
     281            {
     282                /* Need to type convert it. */
     283                if (fChangeRecord)
     284                    rc = RTEnvCreateChangeRecord(&hNewEnv);
     285                else
     286                    rc = RTEnvCreate(&hNewEnv);
     287                if (RT_SUCCESS(rc))
     288                {
     289                    rc = RTEnvApplyChanges(hNewEnv, rThat.m_hEnv);
     290                    if (RT_FAILURE(rc))
     291                        RTEnvDestroy(hNewEnv);
     292                }
     293            }
     294
     295        }
     296        if (RT_SUCCESS(rc))
     297        {
     298            RTEnvDestroy(m_hEnv);
     299            m_hEnv = hNewEnv;
     300        }
     301        return rc;
     302    }
     303
     304
     305    /** The environment change record. */
     306    RTENV       m_hEnv;
     307};
     308
     309
     310#if 0 /* Not currently used. */
     311/**
     312 * Wrapper around the RTEnv API for a normal environment.
     313 */
     314class GuestEnvironment : public GuestEnvironmentBase
     315{
     316public:
     317    /**
     318     * Default constructor.
     319     *
     320     * The user must invoke one of the init methods before using the object.
     321     */
     322    GuestEnvironment(void)
     323        : GuestEnvironmentBase()
     324    { }
     325
     326    /**
     327     * Copy operator.
     328     * @param   rThat       The object to copy.
     329     * @throws HRESULT
     330     */
     331    GuestEnvironment(const GuestEnvironment &rThat)
     332        : GuestEnvironmentBase(rThat, false /*fChangeRecord*/)
     333    { }
     334
     335    /**
     336     * Copy operator.
     337     * @param   rThat       The object to copy.
     338     * @throws HRESULT
     339     */
     340    GuestEnvironment(const GuestEnvironmentBase &rThat)
     341        : GuestEnvironmentBase(rThat, false /*fChangeRecord*/)
     342    { }
     343
     344    /**
     345     * Initialize this as a normal environment block.
     346     * @returns IPRT status code.
     347     */
     348    int initNormal(void)
     349    {
     350        AssertReturn(m_hEnv == NIL_RTENV, VERR_WRONG_ORDER);
     351        return RTEnvCreate(&m_hEnv);
     352    }
     353
     354    /**
     355     * Replaces this environemnt with that in @a rThat.
     356     *
     357     * @returns IPRT status code
     358     * @param   rThat       The environment to copy. If it's a different type
     359     *                      we'll convert the data to a normal environment block.
     360     */
     361    int copy(const GuestEnvironmentBase &rThat)
     362    {
     363        return cloneCommon(rThat, false /*fChangeRecord*/);
     364    }
     365};
     366#endif /* unused */
     367
     368
     369/**
     370 * Wrapper around the RTEnv API for a environment change record.
     371 *
     372 * This class is used as a record of changes to be applied to a different
     373 * environment block (in VBoxService before launching a new process).
     374 */
     375class GuestEnvironmentChanges : public GuestEnvironmentBase
     376{
     377public:
     378    /**
     379     * Default constructor.
     380     *
     381     * The user must invoke one of the init methods before using the object.
     382     */
     383    GuestEnvironmentChanges(void)
     384        : GuestEnvironmentBase()
     385    { }
     386
     387    /**
     388     * Copy operator.
     389     * @param   rThat       The object to copy.
     390     * @throws HRESULT
     391     */
     392    GuestEnvironmentChanges(const GuestEnvironmentChanges &rThat)
     393        : GuestEnvironmentBase(rThat, true /*fChangeRecord*/)
     394    { }
     395
     396    /**
     397     * Copy operator.
     398     * @param   rThat       The object to copy.
     399     * @throws HRESULT
     400     */
     401    GuestEnvironmentChanges(const GuestEnvironmentBase &rThat)
     402        : GuestEnvironmentBase(rThat, true /*fChangeRecord*/)
     403    { }
     404
     405    /**
     406     * Initialize this as a environment change record.
     407     * @returns IPRT status code.
     408     */
     409    int initChangeRecord(void)
     410    {
     411        AssertReturn(m_hEnv == NIL_RTENV, VERR_WRONG_ORDER);
     412        return RTEnvCreateChangeRecord(&m_hEnv);
     413    }
     414
     415    /**
     416     * Replaces this environemnt with that in @a rThat.
     417     *
     418     * @returns IPRT status code
     419     * @param   rThat       The environment to copy. If it's a different type
     420     *                      we'll convert the data to a set of changes.
     421     */
     422    int copy(const GuestEnvironmentBase &rThat)
     423    {
     424        return cloneCommon(rThat, true /*fChangeRecord*/);
     425    }
    104426};
    105427
     
    225547    /** Arguments vector (starting with argument \#0). */
    226548    ProcessArguments            mArguments;
    227     GuestEnvironment            mEnvironment;
     549    /** The process environment change record.  */
     550    GuestEnvironmentChanges     mEnvironment;
    228551    /** Process creation flags. */
    229552    uint32_t                    mFlags;
  • trunk/src/VBox/Main/include/GuestSessionImpl.h

    r55541 r55588  
    391391public:
    392392    /** @name Public internal methods.
     393     * @todo r=bird: Most of these are public for no real reason...
    393394     * @{ */
    394395    int                     i_closeSession(uint32_t uFlags, uint32_t uTimeoutMS, int *pGuestRc);
     
    415416    int                     i_fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc);
    416417    const GuestCredentials &i_getCredentials(void);
    417     const GuestEnvironment &i_getEnvironment(void);
    418418    EventSource            *i_getEventSource(void) { return mEventSource; }
    419419    Utf8Str                 i_getName(void);
     
    441441    int                     i_startTaskAsync(const Utf8Str &strTaskDesc, GuestSessionTask *pTask,
    442442                                             ComObjPtr<Progress> &pProgress);
    443     int                     i_queryInfo(void);
     443    int                     i_determineProtocolVersion(void);
    444444    int                     i_waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestSessionWaitResult_T &waitResult, int *pGuestRc);
    445445    int                     i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS,
     
    470470        /** The session's current status. */
    471471        GuestSessionStatus_T        mStatus;
    472         /** The session's environment block. Can be
    473          *  overwritten/extended by ProcessCreate(Ex). */
    474         GuestEnvironment            mEnvironment;
     472        /** The set of environment changes for the session for use when
     473         *  creating new guest processes. */
     474        GuestEnvironmentChanges     mEnvironment;
    475475        /** Directory objects bound to this session. */
    476476        SessionDirectories          mDirectories;
  • trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp

    r52981 r55588  
    11/* $Id$ */
    22/** @file
    3  *
    43 * Internal helpers/structures for guest control functionality.
    54 */
    65
    76/*
    8  * Copyright (C) 2011-2014 Oracle Corporation
     7 * Copyright (C) 2011-2015 Oracle Corporation
    98 *
    109 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3736#include <VBox/log.h>
    3837
    39 /******************************************************************************
    40  *   Structures and Typedefs                                                  *
    41  ******************************************************************************/
    42 
    43 int GuestEnvironment::BuildEnvironmentBlock(void **ppvEnv, size_t *pcbEnv, uint32_t *pcEnvVars)
    44 {
    45     AssertPtrReturn(ppvEnv, VERR_INVALID_POINTER);
    46     /* Rest is optional. */
    47 
    48     size_t cbEnv = 0;
    49     uint32_t cEnvVars = 0;
    50 
    51     int rc = VINF_SUCCESS;
    52 
    53     size_t cEnv = mEnvironment.size();
    54     if (cEnv)
    55     {
    56         std::map<Utf8Str, Utf8Str>::const_iterator itEnv = mEnvironment.begin();
    57         for (; itEnv != mEnvironment.end() && RT_SUCCESS(rc); itEnv++)
    58         {
    59             char *pszEnv;
    60             if (!RTStrAPrintf(&pszEnv, "%s=%s", itEnv->first.c_str(), itEnv->second.c_str()))
    61             {
    62                 rc = VERR_NO_MEMORY;
    63                 break;
    64             }
    65             AssertPtr(pszEnv);
    66             rc = appendToEnvBlock(pszEnv, ppvEnv, &cbEnv, &cEnvVars);
    67             RTStrFree(pszEnv);
    68         }
    69         Assert(cEnv == cEnvVars);
    70     }
    71 
    72     if (pcbEnv)
    73         *pcbEnv = cbEnv;
    74     if (pcEnvVars)
    75         *pcEnvVars = cEnvVars;
    76 
    77     return rc;
    78 }
    79 
    80 void GuestEnvironment::Clear(void)
    81 {
    82     mEnvironment.clear();
    83 }
    84 
    85 int GuestEnvironment::CopyFrom(const GuestEnvironmentArray &environment)
    86 {
    87     int rc = VINF_SUCCESS;
    88 
    89     for (GuestEnvironmentArray::const_iterator it = environment.begin();
    90          it != environment.end() && RT_SUCCESS(rc);
    91          ++it)
    92     {
    93         rc = Set((*it));
    94     }
    95 
    96     return rc;
    97 }
    98 
    99 int GuestEnvironment::CopyTo(GuestEnvironmentArray &environment)
    100 {
    101     size_t s = 0;
    102     for (std::map<Utf8Str, Utf8Str>::const_iterator it = mEnvironment.begin();
    103          it != mEnvironment.end();
    104          ++it, ++s)
    105     {
    106         environment[s] = Bstr(it->first + "=" + it->second).raw();
    107     }
    108 
    109     return VINF_SUCCESS;
    110 }
    111 
    112 /* static */
    113 void GuestEnvironment::FreeEnvironmentBlock(void *pvEnv)
    114 {
    115     if (pvEnv)
    116         RTMemFree(pvEnv);
    117 }
    118 
    119 Utf8Str GuestEnvironment::Get(size_t nPos)
    120 {
    121     size_t curPos = 0;
    122     std::map<Utf8Str, Utf8Str>::const_iterator it = mEnvironment.begin();
    123     for (; it != mEnvironment.end() && curPos < nPos;
    124          ++it, ++curPos) { }
    125 
    126     if (it != mEnvironment.end())
    127         return Utf8Str(it->first + "=" + it->second);
    128 
    129     return Utf8Str("");
    130 }
    131 
    132 Utf8Str GuestEnvironment::Get(const Utf8Str &strKey)
    133 {
    134     std::map <Utf8Str, Utf8Str>::const_iterator itEnv = mEnvironment.find(strKey);
    135     Utf8Str strRet;
    136     if (itEnv != mEnvironment.end())
    137         strRet = itEnv->second;
    138     return strRet;
    139 }
    140 
    141 bool GuestEnvironment::Has(const Utf8Str &strKey)
    142 {
    143     std::map <Utf8Str, Utf8Str>::const_iterator itEnv = mEnvironment.find(strKey);
    144     return (itEnv != mEnvironment.end());
    145 }
    146 
    147 int GuestEnvironment::Set(const Utf8Str &strKey, const Utf8Str &strValue)
    148 {
    149     /** @todo Do some validation using regex. */
    150     if (strKey.isEmpty())
    151         return VERR_INVALID_PARAMETER;
    152 
    153     int rc = VINF_SUCCESS;
    154     const char *pszString = strKey.c_str();
    155     while (*pszString != '\0' && RT_SUCCESS(rc))
    156     {
    157          if (   !RT_C_IS_ALNUM(*pszString)
    158              && !RT_C_IS_GRAPH(*pszString))
    159              rc = VERR_INVALID_PARAMETER;
    160          *pszString++;
    161     }
    162 
    163     if (RT_SUCCESS(rc))
    164         mEnvironment[strKey] = strValue;
    165 
    166     return rc;
    167 }
    168 
    169 int GuestEnvironment::Set(const Utf8Str &strPair)
    170 {
    171     RTCList<RTCString> listPair = strPair.split("=", RTCString::KeepEmptyParts);
    172     /* Skip completely empty pairs. Note that we still need pairs with a valid
    173      * (set) key and an empty value. */
    174     if (listPair.size() <= 1)
    175         return VINF_SUCCESS;
    176 
    177     int rc = VINF_SUCCESS;
    178     size_t p = 0;
    179     while (p < listPair.size() && RT_SUCCESS(rc))
    180     {
    181         Utf8Str strKey = listPair.at(p++);
    182         if (   strKey.isEmpty()
    183             || strKey.equals("=")) /* Skip pairs with empty keys (e.g. "=FOO"). */
    184         {
    185             break;
    186         }
    187         Utf8Str strValue;
    188         if (p < listPair.size()) /* Does the list also contain a value? */
    189             strValue = listPair.at(p++);
    190 
    191 #ifdef DEBUG
    192         LogFlowFunc(("strKey=%s, strValue=%s\n",
    193                      strKey.c_str(), strValue.c_str()));
    194 #endif
    195         rc = Set(strKey, strValue);
    196     }
    197 
    198     return rc;
    199 }
    200 
    201 size_t GuestEnvironment::Size(void)
    202 {
    203     return mEnvironment.size();
    204 }
    205 
    206 int GuestEnvironment::Unset(const Utf8Str &strKey)
    207 {
    208     std::map <Utf8Str, Utf8Str>::iterator itEnv = mEnvironment.find(strKey);
    209     if (itEnv != mEnvironment.end())
    210     {
    211         mEnvironment.erase(itEnv);
    212         return VINF_SUCCESS;
    213     }
    214 
    215     return VERR_NOT_FOUND;
    216 }
    217 
    218 GuestEnvironment& GuestEnvironment::operator=(const GuestEnvironmentArray &that)
    219 {
    220     CopyFrom(that);
    221     return *this;
    222 }
    223 
    224 GuestEnvironment& GuestEnvironment::operator=(const GuestEnvironment &that)
    225 {
    226     for (std::map<Utf8Str, Utf8Str>::const_iterator it = that.mEnvironment.begin();
    227          it != that.mEnvironment.end();
    228          ++it)
    229     {
    230         mEnvironment[it->first] = it->second;
    231     }
    232 
    233     return *this;
    234 }
    235 
    236 /**
    237  * Appends environment variables to the environment block.
    238  *
    239  * Each var=value pair is separated by the null character ('\\0').  The whole
    240  * block will be stored in one blob and disassembled on the guest side later to
    241  * fit into the HGCM param structure.
    242  *
    243  * @returns VBox status code.
    244  *
    245  * @param   pszEnvVar       The environment variable=value to append to the
    246  *                          environment block.
    247  * @param   ppvList         This is actually a pointer to a char pointer
    248  *                          variable which keeps track of the environment block
    249  *                          that we're constructing.
    250  * @param   pcbList         Pointer to the variable holding the current size of
    251  *                          the environment block.  (List is a misnomer, go
    252  *                          ahead a be confused.)
    253  * @param   pcEnvVars       Pointer to the variable holding count of variables
    254  *                          stored in the environment block.
    255  */
    256 int GuestEnvironment::appendToEnvBlock(const char *pszEnv, void **ppvList, size_t *pcbList, uint32_t *pcEnvVars)
    257 {
    258     int rc = VINF_SUCCESS;
    259     size_t cchEnv = strlen(pszEnv); Assert(cchEnv >= 2);
    260     if (*ppvList)
    261     {
    262         size_t cbNewLen = *pcbList + cchEnv + 1; /* Include zero termination. */
    263         char *pvTmp = (char *)RTMemRealloc(*ppvList, cbNewLen);
    264         if (pvTmp == NULL)
    265             rc = VERR_NO_MEMORY;
    266         else
    267         {
    268             memcpy(pvTmp + *pcbList, pszEnv, cchEnv);
    269             pvTmp[cbNewLen - 1] = '\0'; /* Add zero termination. */
    270             *ppvList = (void **)pvTmp;
    271         }
    272     }
    273     else
    274     {
    275         char *pszTmp;
    276         if (RTStrAPrintf(&pszTmp, "%s", pszEnv) >= 0)
    277         {
    278             *ppvList = (void **)pszTmp;
    279             /* Reset counters. */
    280             *pcEnvVars = 0;
    281             *pcbList = 0;
    282         }
    283     }
    284     if (RT_SUCCESS(rc))
    285     {
    286         *pcbList += cchEnv + 1; /* Include zero termination. */
    287         *pcEnvVars += 1;        /* Increase env variable count. */
    288     }
    289     return rc;
    290 }
     38
    29139
    29240int GuestFsObjData::FromLs(const GuestProcessStreamBlock &strmBlk)
  • trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp

    r55540 r55588  
    304304
    305305    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    306     mData.mProcess.mEnvironment.CopyTo(aEnvironment);
     306    mData.mProcess.mEnvironment.queryPutEnvArray(&aEnvironment);
    307307    return S_OK;
    308308#endif /* VBOX_WITH_GUEST_CONTROL */
     
    10541054
    10551055    /* Prepare environment. */
    1056     void *pvEnv = NULL;
    1057     size_t cbEnv = 0;
     1056    size_t  cbEnvBlock;
     1057    char   *pszzEnvBlock;
    10581058    if (RT_SUCCESS(vrc))
    1059         vrc = mData.mProcess.mEnvironment.BuildEnvironmentBlock(&pvEnv, &cbEnv, NULL /* cEnv */);
     1059        vrc = mData.mProcess.mEnvironment.queryUtf8Block(&pszzEnvBlock, &cbEnvBlock);
    10601060
    10611061    if (RT_SUCCESS(vrc))
     
    10651065        int i = 0;
    10661066        paParms[i++].setUInt32(pEvent->ContextID());
    1067         paParms[i++].setPointer((void*)mData.mProcess.mExecutable.c_str(),
    1068                                 (ULONG)mData.mProcess.mExecutable.length() + 1);
     1067        paParms[i++].setCppString(mData.mProcess.mExecutable);
    10691068        paParms[i++].setUInt32(mData.mProcess.mFlags);
    10701069        paParms[i++].setUInt32((uint32_t)mData.mProcess.mArguments.size());
    1071         paParms[i++].setPointer((void*)pszArgs, (uint32_t)cbArgs);
    1072         paParms[i++].setUInt32((uint32_t)mData.mProcess.mEnvironment.Size());
    1073         paParms[i++].setUInt32((uint32_t)cbEnv);
    1074         paParms[i++].setPointer((void*)pvEnv, (uint32_t)cbEnv);
     1070        paParms[i++].setPointer(pszArgs, (uint32_t)cbArgs);
     1071        paParms[i++].setUInt32(mData.mProcess.mEnvironment.count());
     1072        paParms[i++].setUInt32((uint32_t)cbEnvBlock);
     1073        paParms[i++].setPointer(pszzEnvBlock, (uint32_t)cbEnvBlock);
    10751074        if (uProtocol < 2)
    10761075        {
     
    10781077             * call. In newer protocols these credentials are part of the opened guest
    10791078             * session, so not needed anymore here. */
    1080             paParms[i++].setPointer((void*)sessionCreds.mUser.c_str(), (ULONG)sessionCreds.mUser.length() + 1);
    1081             paParms[i++].setPointer((void*)sessionCreds.mPassword.c_str(), (ULONG)sessionCreds.mPassword.length() + 1);
     1079            paParms[i++].setCppString(sessionCreds.mUser);
     1080            paParms[i++].setCppString(sessionCreds.mPassword);
    10821081        }
    10831082        /*
     
    10981097            paParms[i++].setUInt32(1);
    10991098            /* The actual CPU affinity blocks. */
    1100             paParms[i++].setPointer((void*)&mData.mProcess.mAffinity, sizeof(mData.mProcess.mAffinity));
     1099            paParms[i++].setPointer((void *)&mData.mProcess.mAffinity, sizeof(mData.mProcess.mAffinity));
    11011100        }
    11021101
     
    11091108            AssertRC(rc2);
    11101109        }
    1111     }
    1112 
    1113     GuestEnvironment::FreeEnvironmentBlock(pvEnv);
     1110
     1111        mData.mProcess.mEnvironment.freeUtf8Block(pszzEnvBlock);
     1112    }
     1113
    11141114    if (pszArgs)
    11151115        RTStrFree(pszArgs);
  • trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp

    r55535 r55588  
    183183    AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
    184184
     185    /*
     186     * Initialize our data members from the input.
     187     */
    185188    mParent = pGuest;
    186189
     
    198201    mData.mCredentials.mDomain = guestCreds.mDomain;
    199202
     203    /* Initialize the remainder of the data. */
    200204    mData.mRC = VINF_SUCCESS;
    201205    mData.mStatus = GuestSessionStatus_Undefined;
    202206    mData.mNumObjects = 0;
    203 
    204     HRESULT hr;
    205 
    206     int rc = i_queryInfo();
     207    int rc = mData.mEnvironment.initNormal();
    207208    if (RT_SUCCESS(rc))
    208209    {
    209         hr = unconst(mEventSource).createObject();
    210         if (FAILED(hr))
    211             rc = VERR_NO_MEMORY;
    212         else
    213         {
     210        rc = RTCritSectInit(&mWaitEventCritSect);
     211        AssertRC(rc);
     212    }
     213    if (RT_SUCCESS(rc))
     214        rc = i_determineProtocolVersion();
     215    if (RT_SUCCESS(rc))
     216    {
     217        /*
     218         * <Replace this if you figure out what the code is doing.>
     219         */
     220        HRESULT hr = unconst(mEventSource).createObject();
     221        if (SUCCEEDED(hr))
    214222            hr = mEventSource->init();
    215             if (FAILED(hr))
    216                 rc = VERR_COM_UNEXPECTED;
    217         }
    218     }
    219 
    220     if (RT_SUCCESS(rc))
    221     {
    222         try
    223         {
    224             GuestSessionListener *pListener = new GuestSessionListener();
    225             ComObjPtr<GuestSessionListenerImpl> thisListener;
    226             hr = thisListener.createObject();
    227             if (SUCCEEDED(hr))
    228                 hr = thisListener->init(pListener, this);
    229 
    230             if (SUCCEEDED(hr))
     223        if (SUCCEEDED(hr))
     224        {
     225            try
    231226            {
    232                 com::SafeArray <VBoxEventType_T> eventTypes;
    233                 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
    234                 hr = mEventSource->RegisterListener(thisListener,
    235                                                     ComSafeArrayAsInParam(eventTypes),
    236                                                     TRUE /* Active listener */);
     227                GuestSessionListener *pListener = new GuestSessionListener();
     228                ComObjPtr<GuestSessionListenerImpl> thisListener;
     229                hr = thisListener.createObject();
     230                if (SUCCEEDED(hr))
     231                    hr = thisListener->init(pListener, this);
    237232                if (SUCCEEDED(hr))
    238233                {
    239                     mLocalListener = thisListener;
    240 
    241                     rc = RTCritSectInit(&mWaitEventCritSect);
    242                     AssertRC(rc);
     234                    com::SafeArray <VBoxEventType_T> eventTypes;
     235                    eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
     236                    hr = mEventSource->RegisterListener(thisListener,
     237                                                        ComSafeArrayAsInParam(eventTypes),
     238                                                        TRUE /* Active listener */);
     239                    if (SUCCEEDED(hr))
     240                    {
     241                        mLocalListener = thisListener;
     242
     243                        /*
     244                         * Mark this object as operational and return success.
     245                         */
     246                        autoInitSpan.setSucceeded();
     247                        LogFlowThisFunc(("mName=%s mID=%RU32 mIsInternal=%RTbool rc=VINF_SUCCESS\n",
     248                                         mData.mSession.mName.c_str(), mData.mSession.mID, mData.mSession.mIsInternal));
     249                        return VINF_SUCCESS;
     250                    }
    243251                }
    244                 else
    245                     rc = VERR_COM_UNEXPECTED;
    246252            }
    247             else
    248                 rc = VERR_COM_UNEXPECTED;
    249         }
    250         catch(std::bad_alloc &)
    251         {
    252             rc = VERR_NO_MEMORY;
    253         }
    254     }
    255 
    256     if (RT_SUCCESS(rc))
    257     {
    258         /* Confirm a successful initialization when it's the case. */
    259         autoInitSpan.setSucceeded();
    260     }
    261     else
    262         autoInitSpan.setFailed();
    263 
    264     LogFlowThisFunc(("mName=%s, mID=%RU32, mIsInternal=%RTbool, rc=%Rrc\n",
    265                      mData.mSession.mName.c_str(), mData.mSession.mID, mData.mSession.mIsInternal, rc));
     253            catch (std::bad_alloc &)
     254            {
     255                hr = E_OUTOFMEMORY;
     256            }
     257        }
     258        rc = Global::vboxStatusCodeFromCOM(hr);
     259    }
     260
     261    autoInitSpan.setFailed();
     262    LogThisFunc(("Failed! mName=%s mID=%RU32 mIsInternal=%RTbool => rc=%Rrc\n",
     263                 mData.mSession.mName.c_str(), mData.mSession.mID, mData.mSession.mIsInternal, rc));
    266264    return rc;
    267265#endif /* VBOX_WITH_GUEST_CONTROL */
     
    322320    mData.mProcesses.clear();
    323321
     322    mData.mEnvironment.reset();
     323
    324324    AssertMsg(mData.mNumObjects == 0,
    325325              ("mNumObjects=%RU32 when it should be 0\n", mData.mNumObjects));
     
    471471    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    472472
    473     size_t cEnvVars = mData.mEnvironment.Size();
    474     aEnvironment.resize(cEnvVars);
    475 
    476     LogFlowThisFunc(("[%s]: cEnvVars=%RU32\n",
    477                      mData.mSession.mName.c_str(), cEnvVars));
    478 
    479     for (size_t i = 0; i < cEnvVars; i++)
    480         aEnvironment[i] = mData.mEnvironment.Get(i);
    481 
    482     LogFlowThisFuncLeave();
    483     return S_OK;
     473    int vrc = mData.mEnvironment.queryPutEnvArray(&aEnvironment);
     474
     475    LogFlowFuncLeaveRC(vrc);
     476    return Global::vboxStatusCodeToCOM(vrc);
    484477#endif /* VBOX_WITH_GUEST_CONTROL */
    485478}
     
    494487    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    495488
    496     int rc = VINF_SUCCESS;
    497     for (size_t i = 0; i < aEnvironment.size() && RT_SUCCESS(rc); ++i)
    498         if (!aEnvironment[i].isEmpty()) /* Silently skip empty entries. */
    499             rc = mData.mEnvironment.Set(aEnvironment[i]);
    500 
    501     HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
    502     LogFlowFuncLeaveRC(hr);
    503     return hr;
     489    mData.mEnvironment.reset();
     490    int vrc = mData.mEnvironment.applyPutEnvArray(aEnvironment);
     491
     492    LogFlowFuncLeaveRC(vrc);
     493    return Global::vboxStatusCodeToCOM(vrc);
    504494#endif /* VBOX_WITH_GUEST_CONTROL */
    505495}
     
    14141404{
    14151405    return mData.mCredentials;
    1416 }
    1417 
    1418 const GuestEnvironment& GuestSession::i_getEnvironment(void)
    1419 {
    1420     return mData.mEnvironment;
    14211406}
    14221407
     
    21182103
    21192104/**
    2120  * Queries/collects information prior to establishing a guest session.
    2121  * This is necessary to know which guest control protocol version to use,
    2122  * among other things (later).
     2105 * Determines the protocol version (sets mData.mProtocolVersion).
     2106 *
     2107 * This is called from the init method prior to to establishing a guest
     2108 * session.
    21232109 *
    21242110 * @return  IPRT status code.
    21252111 */
    2126 int GuestSession::i_queryInfo(void)
     2112int GuestSession::i_determineProtocolVersion(void)
    21272113{
    21282114    /*
    2129      * Try querying the guest control protocol version running on the guest.
    2130      * This is done using the Guest Additions version
     2115     * We currently do this based on the reported guest additions version,
     2116     * ASSUMING that VBoxService and VBoxDrv are at the same version.
    21312117     */
    21322118    ComObjPtr<Guest> pGuest = mParent;
    2133     Assert(!pGuest.isNull());
    2134 
    2135     uint32_t uVerAdditions = pGuest->i_getAdditionsVersion();
    2136     uint32_t uVBoxMajor    = VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions);
    2137     uint32_t uVBoxMinor    = VBOX_FULL_VERSION_GET_MINOR(uVerAdditions);
    2138 
    2139 #ifdef DEBUG_andy
    2140     /* Hardcode the to-used protocol version; nice for testing side effects. */
    2141     mData.mProtocolVersion = 2;
    2142 #else
    2143     mData.mProtocolVersion = (
    2144                               /* VBox 5.0 and up. */
    2145                                  uVBoxMajor  >= 5
    2146                               /* VBox 4.3 and up. */
    2147                               || (uVBoxMajor == 4 && uVBoxMinor >= 3))
    2148                            ? 2  /* Guest control 2.0. */
    2149                            : 1; /* Legacy guest control (VBox < 4.3). */
    2150     /* Build revision is ignored. */
    2151 #endif
    2152 
    2153     LogFlowThisFunc(("uVerAdditions=%RU32 (%RU32.%RU32), mProtocolVersion=%RU32\n",
    2154                      uVerAdditions, uVBoxMajor, uVBoxMinor, mData.mProtocolVersion));
    2155 
    2156     /* Tell the user but don't bitch too often. */
    2157     /** @todo Find a bit nicer text. */
     2119    AssertReturn(!pGuest.isNull(), VERR_NOT_SUPPORTED);
     2120    uint32_t uGaVersion = pGuest->i_getAdditionsVersion();
     2121
     2122    /* Everyone supports version one, if they support anything at all. */
     2123    mData.mProtocolVersion = 1;
     2124
     2125    /* Guest control 2.0 was introduced with 4.3.0. */
     2126    if (uGaVersion >= VBOX_FULL_VERSION_MAKE(4,3,0))
     2127        mData.mProtocolVersion = 2; /* Guest control 2.0. */
     2128
     2129    LogFlowThisFunc(("uGaVersion=%u.%u.%u => mProtocolVersion=%u\n",
     2130                     VBOX_FULL_VERSION_GET_MAJOR(uGaVersion), VBOX_FULL_VERSION_GET_MINOR(uGaVersion),
     2131                     VBOX_FULL_VERSION_GET_BUILD(uGaVersion), mData.mProtocolVersion));
     2132
     2133    /*
     2134     * Inform the user about outdated guest additions (VM release log).
     2135     */
    21582136    if (mData.mProtocolVersion < 2)
    2159         LogRelMax(3, (tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"),
    2160                     uVBoxMajor, uVBoxMinor, mData.mProtocolVersion));
     2137        LogRelMax(3, (tr("Warning: Guest Additions v%u.%u.%u only supports the older guest control protocol version %u.\n"
     2138                         "         Please upgrade GAs to the current version to get full guest control capabilities.\n"),
     2139                      VBOX_FULL_VERSION_GET_MAJOR(uGaVersion), VBOX_FULL_VERSION_GET_MINOR(uGaVersion),
     2140                      VBOX_FULL_VERSION_GET_BUILD(uGaVersion), mData.mProtocolVersion));
    21612141
    21622142    return VINF_SUCCESS;
     
    29242904}
    29252905
     2906/** @todo remove this it duplicates the 'environment' attribute.   */
    29262907HRESULT GuestSession::environmentClear()
    29272908{
     
    29332914    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    29342915
    2935     mData.mEnvironment.Clear();
     2916    mData.mEnvironment.reset();
    29362917
    29372918    LogFlowThisFuncLeave();
     
    29402921}
    29412922
     2923/** @todo Remove this because the interface isn't suitable for returning 'unset'
     2924 *        or empty values, and it can easily be misunderstood.  Besides there
     2925 *        is hardly a usecase for it as long as it just works on
     2926 *        environment changes and there is the 'environment' attribute. */
    29422927HRESULT GuestSession::environmentGet(const com::Utf8Str &aName, com::Utf8Str &aValue)
    29432928{
     
    29472932    LogFlowThisFuncEnter();
    29482933
    2949     if (RT_UNLIKELY(aName.c_str() == NULL) || *(aName.c_str()) == '\0')
    2950         return setError(E_INVALIDARG, tr("No value name specified"));
    2951 
    2952     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2953 
    2954     aValue =  mData.mEnvironment.Get(aName);
     2934    HRESULT hrc;
     2935    if (RT_LIKELY(aName.isNotEmpty()))
     2936    {
     2937        if (RT_LIKELY(strchr(aName.c_str(), '=') == NULL))
     2938        {
     2939            AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     2940
     2941            mData.mEnvironment.getVariable(aName, &aValue);
     2942            hrc = S_OK;
     2943        }
     2944        else
     2945            hrc = setError(E_INVALIDARG, tr("The equal char is not allowed in environment variable names"));
     2946    }
     2947    else
     2948        hrc = setError(E_INVALIDARG, tr("No variable name specified"));
    29552949
    29562950    LogFlowThisFuncLeave();
    2957     return S_OK;
     2951    return hrc;
    29582952#endif /* VBOX_WITH_GUEST_CONTROL */
    29592953}
     
    29662960    LogFlowThisFuncEnter();
    29672961
    2968     if (RT_UNLIKELY((aName.c_str() == NULL) || *(aName.c_str()) == '\0'))
    2969         return setError(E_INVALIDARG, tr("No value name specified"));
    2970 
    2971     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2972 
    2973     int rc = mData.mEnvironment.Set(aName, aValue);
    2974 
    2975     HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
    2976     LogFlowFuncLeaveRC(hr);
    2977     return hr;
     2962    HRESULT hrc;
     2963    if (RT_LIKELY(aName.isNotEmpty()))
     2964    {
     2965        if (RT_LIKELY(strchr(aName.c_str(), '=') == NULL))
     2966        {
     2967            AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     2968            int vrc = mData.mEnvironment.setVariable(aName, aValue);
     2969            if (RT_SUCCESS(vrc))
     2970                hrc = S_OK;
     2971            else
     2972                hrc = setErrorVrc(vrc);
     2973        }
     2974        else
     2975            hrc = setError(E_INVALIDARG, tr("The equal char is not allowed in environment variable names"));
     2976    }
     2977    else
     2978        hrc = setError(E_INVALIDARG, tr("No variable name specified"));
     2979
     2980    LogFlowThisFuncLeave();
     2981    return hrc;
    29782982#endif /* VBOX_WITH_GUEST_CONTROL */
    29792983}
     
    29852989#else
    29862990    LogFlowThisFuncEnter();
    2987 
    2988     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2989 
    2990     mData.mEnvironment.Unset(aName);
     2991    HRESULT hrc;
     2992    if (RT_LIKELY(aName.isNotEmpty()))
     2993    {
     2994        if (RT_LIKELY(strchr(aName.c_str(), '=') == NULL))
     2995        {
     2996            AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     2997            int vrc = mData.mEnvironment.unsetVariable(aName);
     2998            if (RT_SUCCESS(vrc))
     2999                hrc = S_OK;
     3000            else
     3001                hrc = setErrorVrc(vrc);
     3002        }
     3003        else
     3004            hrc = setError(E_INVALIDARG, tr("The equal char is not allowed in environment variable names"));
     3005    }
     3006    else
     3007        hrc = setError(E_INVALIDARG, tr("No variable name specified"));
    29913008
    29923009    LogFlowThisFuncLeave();
    2993     return S_OK;
     3010    return hrc;
    29943011#endif /* VBOX_WITH_GUEST_CONTROL */
    29953012}
     
    33383355    LogFlowThisFuncEnter();
    33393356
     3357    /** @todo r=bird: Check input better? aPriority is passed on to the guest
     3358     * without any validation.  Flags not existing in this vbox version are
     3359     * ignored, potentially doing something entirely different than what the
     3360     * caller had in mind. */
     3361
    33403362    /*
    33413363     * Must have an executable to execute.  If none is given, we try use the
     
    33693391            procInfo.mArguments.push_back(aArguments[i]);
    33703392
    3371     /*
    3372      * Create the process environment:
    3373      * - Apply the session environment in a first step, and
    3374      * - Apply environment variables specified by this call to
    3375      *   have the chance of overwriting/deleting session entries.
    3376      */
    3377     procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
    3378 
    3379     int rc = VINF_SUCCESS;
    3380     if (aEnvironment.size())
    3381         for (size_t i = 0; i < aEnvironment.size() && RT_SUCCESS(rc); i++)
    3382         {
    3383             /** @todo r=bird: What ARE you trying to do here??? The documentation is crystal
    3384              *        clear on that each entry contains ONE pair, however,
    3385              *        GuestEnvironment::Set(const Utf8Str &) here will split up the input
    3386              *        into any number of pairs, from what I can tell.  Such that for e.g.
    3387              *        "VBOX_LOG_DEST=file=/tmp/foobared.log" becomes "VBOX_LOG_DEST=file"
    3388              *        and "/tmp/foobared.log" - which I obviously don't want! */
    3389             rc = procInfo.mEnvironment.Set(aEnvironment[i]);
    3390         }
    3391 
    3392     if (RT_SUCCESS(rc))
     3393    /* Combine the environment changes associated with the ones passed in by
     3394       the caller, giving priority to the latter.  The changes are putenv style
     3395       and will be applied to the standard environment for the guest user. */
     3396    int vrc = procInfo.mEnvironment.copy(mData.mEnvironment);
     3397    if (RT_SUCCESS(vrc))
     3398        vrc = procInfo.mEnvironment.applyPutEnvArray(aEnvironment);
     3399    if (RT_SUCCESS(vrc))
    33933400    {
    33943401        /* Convert the flag array into a mask. */
     
    34113418         */
    34123419        ComObjPtr<GuestProcess> pProcess;
    3413         rc = i_processCreateExInternal(procInfo, pProcess);
    3414         if (RT_SUCCESS(rc))
     3420        vrc = i_processCreateExInternal(procInfo, pProcess);
     3421        if (RT_SUCCESS(vrc))
    34153422        {
    34163423            /* Return guest session to the caller. */
    3417             HRESULT hr2 = pProcess.queryInterfaceTo(aGuestProcess.asOutParam());
    3418             if (SUCCEEDED(hr2))
     3424            hr = pProcess.queryInterfaceTo(aGuestProcess.asOutParam());
     3425            if (SUCCEEDED(hr))
    34193426            {
    34203427                /*
    34213428                 * Start the process.
    34223429                 */
    3423                 rc = pProcess->i_startProcessAsync();
    3424                 if (RT_FAILURE(rc))
     3430                vrc = pProcess->i_startProcessAsync();
     3431                if (RT_SUCCESS(vrc))
    34253432                {
    3426                     /** @todo r=bird: What happens to the interface that *aGuestProcess points to
    3427                      *        now?  Looks like a leak or an undocument hack of sorts... */
     3433                    LogFlowFuncLeaveRC(vrc);
     3434                    return S_OK;
    34283435                }
     3436
     3437                hr = setErrorVrc(vrc, tr("Failed to start guest process: %Rrc"), vrc);
     3438                /** @todo r=bird: What happens to the interface that *aGuestProcess points to
     3439                 *        now?  Looks like a leak or an undocument hack of sorts... */
    34293440            }
    3430             else
    3431                 rc = VERR_COM_OBJECT_NOT_FOUND;
    3432         }
    3433     }
    3434 
    3435     /** @todo you're better off doing this is 'else if (rc == xxx') statements,
    3436      *        since there is just one place where you'll get
    3437      *        VERR_MAX_PROCS_REACHED in the above code. */
    3438     if (RT_FAILURE(rc))
    3439     {
    3440         switch (rc)
    3441         {
    3442             case VERR_MAX_PROCS_REACHED:
    3443                 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest processes per session (%ld) reached"),
    3444                                                     VBOX_GUESTCTRL_MAX_OBJECTS);
    3445                 break;
    3446 
    3447             /** @todo Add more errors here. */
    3448 
    3449             default:
    3450                 hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);
    3451                 break;
    3452         }
    3453     }
    3454 
    3455     LogFlowFuncLeaveRC(rc);
     3441        }
     3442        else if (vrc == VERR_MAX_PROCS_REACHED)
     3443            hr = setErrorVrc(vrc, tr("Maximum number of concurrent guest processes per session (%u) reached"),
     3444                             VBOX_GUESTCTRL_MAX_OBJECTS);
     3445        else
     3446            hr = setErrorVrc(vrc, tr("Failed to create guest process object: %Rrc"), vrc);
     3447    }
     3448    else
     3449        hr = setErrorVrc(vrc, tr("Failed to set up the environment: %Rrc"), vrc);
     3450
     3451    LogFlowFuncLeaveRC(vrc);
    34563452    return hr;
    34573453#endif /* VBOX_WITH_GUEST_CONTROL */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette