Changeset 4475
- Timestamp:
- 09/01/07 03:21:19 (1 year ago)
- Files:
-
- trunk/include/iprt/env.h (modified) (4 diffs)
- trunk/include/iprt/err.h (modified) (1 diff)
- trunk/include/iprt/process.h (modified) (1 diff)
- trunk/src/VBox/Main/MachineImpl.cpp (modified) (6 diffs)
- trunk/src/VBox/Main/VirtualBoxImpl.cpp (modified) (2 diffs)
- trunk/src/VBox/Main/linux/server_module.cpp (modified) (2 diffs)
- trunk/src/VBox/Runtime/VBox/RTAssertDoBreakpoint-vbox.cpp (modified) (1 diff)
- trunk/src/VBox/Runtime/generic/env-generic.cpp (modified) (1 diff)
- trunk/src/VBox/Runtime/include/internal/magics.h (modified) (1 diff)
- trunk/src/VBox/Runtime/r3/posix/env-posix.cpp (modified) (2 diffs)
- trunk/src/VBox/Runtime/r3/posix/process-posix.cpp (modified) (3 diffs)
- trunk/src/VBox/Runtime/r3/win32/process-win32.cpp (modified) (2 diffs)
- trunk/src/VBox/Runtime/testcase/Makefile.kmk (modified) (3 diffs)
- trunk/src/VBox/Runtime/testcase/tstEnv.cpp (copied) (copied from trunk/src/VBox/Runtime/testcase/tstLog.cpp) (2 diffs)
- trunk/src/VBox/Runtime/testcase/tstRTProcWait.cpp (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/include/iprt/env.h
r4071 r4475 30 30 #ifdef IN_RING3 31 31 32 33 /** 34 * Checks if an environment variable exists. 35 * 36 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 37 * 38 * @param pszVar The environment variable name. 32 /** Special handle that indicates the default process environment. */ 33 #define RTENV_DEFAULT ((RTENV)~(uintptr_t)0) 34 35 /** 36 * Creates an empty environment block. 37 * 38 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 39 * 40 * @param pEnv Where to store the handle of the new environment block. 41 */ 42 RTDECL(int) RTEnvCreate(PRTENV pEnv); 43 44 /** 45 * Creates an environment block and fill it with variables from the given 46 * environment array. 47 * 48 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 49 * 50 * @param pEnv Where to store the handle of the new environment block. 51 * @param EnvToClone The environment to clone. 52 */ 53 RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone); 54 55 /** 56 * Destroys an environment block. 57 * 58 * @returns IPRT status code. 59 * 60 * @param Env Environment block handle. 61 * Both RTENV_DEFAULT and NIL_RTENV are silently ignored. 62 */ 63 RTDECL(int) RTEnvDestroy(RTENV Env); 64 65 /** 66 * Get the execve/spawnve/main envp. 67 * 68 * All returned strings are in the current process' codepage. 69 * This array is only valid until the next RTEnv call. 70 * 71 * @returns Pointer to the raw array of environment variables. 72 * @returns NULL if Env is NULL or invalid. 73 * 74 * @param Env Environment block handle. 75 */ 76 RTDECL(char const * const *) RTEnvGetExecEnvP(RTENV Env); 77 78 79 /** 80 * Checks if an environment variable exists in the default environment block. 81 * 82 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 83 * 84 * @param pszVar The environment variable name. 85 * @remark WARNING! The current implementation does not perform the appropriate 86 * codeset conversion. We'll figure this out when it becomes necessary. 39 87 */ 40 88 RTDECL(bool) RTEnvExist(const char *pszVar); 41 89 42 90 /** 43 * Gets an environment variable (getenv). 91 * Checks if an environment variable exists in a specific environment block. 92 * 93 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 94 * 95 * @param Env The environment handle. 96 * @param pszVar The environment variable name. 97 */ 98 RTDECL(bool) RTEnvExistEx(RTENV Env, const char *pszVar); 99 100 /** 101 * Gets an environment variable from the default environment block. (getenv). 44 102 * 45 103 * The caller is responsible for ensuring that nobody changes the environment … … 49 107 * 50 108 * @param pszVar The environment variable name. 109 * 110 * @remark WARNING! The current implementation does not perform the appropriate 111 * codeset conversion. We'll figure this out when it becomes necessary. 51 112 */ 52 113 RTDECL(const char *) RTEnvGet(const char *pszVar); 114 115 /** 116 * Gets an environment variable in a specific environment block. 117 * 118 * @returns IPRT status code. 119 * 120 * @param Env The environment handle. 121 * @param pszVar The environment variable name. 122 * @param pszValue Where to put the buffer. 123 * @param cbValue The size of the value buffer. 124 * @param pcchActual Returns the actual value string length. Optional. 125 */ 126 RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual); 53 127 54 128 /** … … 59 133 * @param pszVarEqualValue The variable '=' value string. If the value and '=' is 60 134 * omitted, the variable is removed from the environment. 135 * 136 * @remark Don't assume the value is copied. 137 * @remark WARNING! The current implementation does not perform the appropriate 138 * codeset conversion. We'll figure this out when it becomes necessary. 61 139 */ 62 140 RTDECL(int) RTEnvPut(const char *pszVarEqualValue); 63 141 64 142 /** 65 * Sets an environment variable (setenv(,,1)). 66 * 67 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 68 * 69 * @param pszVar The environment variable name. 70 * @param pszValue The environment variable value. 71 */ 72 RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue); 73 74 /** @todo Add the missing environment APIs: safe, printf like, and various modifications. */ 75 76 /** 77 * Creates an empty environment block. 78 * 79 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 80 * 81 * @param pEnv Where to store the handle of the environment block. 82 */ 83 RTDECL(int) RTEnvCreate(PRTENV pEnv); 84 85 /** 86 * Destroys an environment block. 87 * 88 * @returns IPRT status code. 89 * 90 * @param Env Handle of the environment block. 91 */ 92 RTDECL(int) RTEnvDestroy(RTENV Env); 93 94 /** 95 * Creates an environment block and fill it with variables from the given 96 * environment array. 97 * 98 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 99 * 100 * @param pEnv Where to store the handle of the environment block. 101 * @param apszEnv Pointer to the NULL-terminated array of environment 102 * variables. If NULL, the current process' environment 103 * will be cloned. 104 */ 105 RTDECL(int) RTEnvClone(PRTENV pEnv, char const *const *apszEnv); 106 107 /** @todo later */ 108 /* 109 RTDECL(int) RTEnvCloneEx(PRTENV pEnv, const RTENV Env); 110 111 RTDECL(int) RTEnvExistEx(RTENV Env, const char *pszVar); 112 RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue); 113 RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, const char **ppszValue); 114 RTDECL(int) RTEnvCountEx(RTENV Env, size_t *cbCount); 115 */ 116 117 /** 118 * Puts a 'variable=value' string into the environment. 119 * 120 * The supplied string must be in the current process' codepage. 121 * This function makes a copy of the supplied string. 143 * Puts a copy of the passed in 'variable=value' string into the environment block. 122 144 * 123 145 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. … … 130 152 131 153 /** 132 * Returns a raw pointer to the array of environment variables of the given 133 * environment block where every variable is a string in format 134 * 'variable=value'. 135 * 136 * All returned strings are in the current process' codepage. 137 * 138 * @returns Pointer to the raw array of environment variables. 139 * @returns NULL if Env is NULL or invalid. 140 * 141 * @param Env Handle of the environment block. 142 */ 143 RTDECL(char const *const *) RTEnvGetArray(RTENV Env); 154 * Sets an environment variable (setenv(,,1)). 155 * 156 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 157 * 158 * @param pszVar The environment variable name. 159 * @param pszValue The environment variable value. 160 * 161 * @remark WARNING! The current implementation does not perform the appropriate 162 * codeset conversion. We'll figure this out when it becomes necessary. 163 */ 164 RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue); 165 166 /** 167 * Sets an environment variable (setenv(,,1)). 168 * 169 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 170 * 171 * @param Env The environment handle. 172 * @param pszVar The environment variable name. 173 * @param pszValue The environment variable value. 174 */ 175 RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue); 176 177 /** 178 * Removes an environment variable from the default environment block. 179 * 180 * @returns IPRT status code. 181 * @returns VINF_ENV_VAR_NOT_FOUND if the variable was not found. 182 * 183 * @param pszVar The environment variable name. 184 * 185 * @remark WARNING! The current implementation does not perform the appropriate 186 * codeset conversion. We'll figure this out when it becomes necessary. 187 */ 188 RTDECL(int) RTEnvUnset(const char *pszVar); 189 190 /** 191 * Removes an environment variable from the specified environment block. 192 * 193 * @returns IPRT status code. 194 * @returns VINF_ENV_VAR_NOT_FOUND if the variable was not found. 195 * 196 * @param Env The environment handle. 197 * @param pszVar The environment variable name. 198 */ 199 RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar); 144 200 145 201 #endif /* IN_RING3 */ trunk/include/iprt/err.h
r4071 r4475 819 819 /** @} */ 820 820 821 /** @name Environment Status Code 822 * @{ 823 */ 824 /** The specified environment variable was not found. (RTEnvGetEx) */ 825 #define VERR_ENV_VAR_NOT_FOUND (-750) 826 /** The specified environment variable was not found. (RTEnvUnsetEx) */ 827 #define VINF_ENV_VAR_NOT_FOUND (750) 828 /** @} */ 829 821 830 /* SED-END */ 822 831 trunk/include/iprt/process.h
r4071 r4475 117 117 * @param pszExec Executable image to use to create the child process. 118 118 * @param papszArgs Pointer to an array of arguments to the child. The array terminated by an entry containing NULL. 119 * @param papszEnv Pointer to array of environment variables for the child process. An NULL entry 120 * terminates the array. The variables are on the form '\<var\>=\<value\>'. 121 * If NULL the environment of the process will be used. 119 * @param Env Handle to the environment block for the child. 122 120 * @param fFlags Flags. This is currently reserved and must be 0. 123 121 * @param pProcess Where to store the process identifier on successful return. 124 122 * The content is not changed on failure. NULL is allowed. 125 123 */ 126 RTR3DECL(int) RTProcCreate(const char *pszExec, const char * const *papszArgs, const char * const *papszEnv, unsigned fFlags, PRTPROCESS pProcess);124 RTR3DECL(int) RTProcCreate(const char *pszExec, const char * const *papszArgs, RTENV Env, unsigned fFlags, PRTPROCESS pProcess); 127 125 128 126 /** trunk/src/VBox/Main/MachineImpl.cpp
r4306 r4475 2809 2809 RTPROCESS pid = NIL_RTPROCESS; 2810 2810 2811 RTENV env = NIL_RTENV;2811 RTENV env = RTENV_DEFAULT; 2812 2812 2813 2813 if (aEnvironment) … … 2818 2818 { 2819 2819 /* clone the current environment */ 2820 int vrc = RTEnvClone(&env, NULL);2821 AssertRCBreak (vrc , vrc = vrc);2822 2823 vrc = RTStrUtf8ToCurrentCP (&newEnvStr,Utf8Str (aEnvironment));2824 Assert RCBreak (vrc, vrc = vrc);2820 int vrc2 = RTEnvClone (&env, RTENV_DEFAULT); 2821 AssertRCBreak (vrc2, vrc = vrc2); 2822 2823 newEnvStr = RTStrDup(Utf8Str (aEnvironment)); 2824 AssertPtrBreak (newEnvStr, vrc = vrc2); 2825 2825 2826 2826 /* put new variables to the environment … … 2834 2834 *p = '\0'; 2835 2835 if (*var) 2836 if (VBOX_FAILURE (vrc = RTEnvPutEx(env, var))) 2836 { 2837 char *val = strchr (var, '='); 2838 if (val) 2839 { 2840 *val++ = '\0'; 2841 vrc2 = RTEnvSetEx (env, var, val); 2842 } 2843 else 2844 vrc2 = RTEnvUnsetEx (env, var); 2845 if (VBOX_FAILURE (vrc2)) 2837 2846 break; 2847 } 2838 2848 var = p + 1; 2839 2849 } 2840 2850 } 2841 if (VBOX_SUCCESS (vrc ) && *var)2842 vrc = RTEnvPutEx(env, var);2843 2844 AssertRCBreak (vrc , vrc = vrc);2851 if (VBOX_SUCCESS (vrc2) && *var) 2852 vrc2 = RTEnvPutEx (env, var); 2853 2854 AssertRCBreak (vrc2, vrc = vrc2); 2845 2855 } 2846 2856 while (0); … … 2868 2878 const char * args[] = {path, "-comment", name, "-startvm", idStr, 0 }; 2869 2879 #endif 2870 vrc = RTProcCreate (path, args, RTEnvGetArray (env), 0, &pid);2880 vrc = RTProcCreate (path, args, env, 0, &pid); 2871 2881 } 2872 2882 else … … 2885 2895 const char * args[] = {path, "-comment", name, "-startvm", idStr, 0 }; 2886 2896 #endif 2887 vrc = RTProcCreate (path, args, RTEnvGetArray (env), 0, &pid);2897 vrc = RTProcCreate (path, args, env, 0, &pid); 2888 2898 } 2889 2899 else … … 2902 2912 const char * args[] = {path, "-comment", name, "-startvm", idStr, "-capture", 0 }; 2903 2913 #endif 2904 vrc = RTProcCreate (path, args, RTEnvGetArray (env), 0, &pid);2914 vrc = RTProcCreate (path, args, env, 0, &pid); 2905 2915 } 2906 2916 else 2907 2917 { 2908 if (env != NIL_RTENV) 2909 RTEnvDestroy (env); 2918 RTEnvDestroy (env); 2910 2919 return setError (E_INVALIDARG, 2911 2920 tr ("Invalid session type: '%ls'"), aType); 2912 2921 } 2913 2922 2914 if (env != NIL_RTENV) 2915 RTEnvDestroy (env); 2923 RTEnvDestroy (env); 2916 2924 2917 2925 if (VBOX_FAILURE (vrc)) trunk/src/VBox/Main/VirtualBoxImpl.cpp
r4260 r4475 44 44 #include <iprt/thread.h> 45 45 #include <iprt/process.h> 46 #include <iprt/env.h> 46 47 #include <iprt/cpputils.h> 47 48 … … 2338 2339 { 2339 2340 const char *args[] = { exePath, "/Helper", client.name(), 0 }; 2340 vrc = RTProcCreate (exePath, args, NULL, 0, &pid);2341 vrc = RTProcCreate (exePath, args, RTENV_DEFAULT, 0, &pid); 2341 2342 if (VBOX_FAILURE (vrc)) 2342 2343 { trunk/src/VBox/Main/linux/server_module.cpp
r4071 r4475 49 49 #include <iprt/path.h> 50 50 #include <iprt/process.h> 51 #include <iprt/env.h> 51 52 #include <iprt/thread.h> 52 53 … … 179 180 const char *args[] = { VBoxSVCPath, "--automate", 0 }; 180 181 RTPROCESS pid = NIL_RTPROCESS; 181 vrc = RTProcCreate (VBoxSVCPath, args, NULL, 0, &pid);182 vrc = RTProcCreate (VBoxSVCPath, args, RTENV_DEFAULT, 0, &pid); 182 183 if (VBOX_FAILURE (vrc)) 183 184 { trunk/src/VBox/Runtime/VBox/RTAssertDoBreakpoint-vbox.cpp
r4071 r4475 87 87 }; 88 88 RTPROCESS Process; 89 int rc = RTProcCreate(apszArgs[0], &apszArgs[0], NULL, 0, &Process);89 int rc = RTProcCreate(apszArgs[0], &apszArgs[0], RTENV_DEFAULT, 0, &Process); 90 90 if (RT_FAILURE(rc)) 91 91 return false; trunk/src/VBox/Runtime/generic/env-generic.cpp
r4474 r4475 23 23 #include <iprt/assert.h> 24 24 #include <iprt/alloc.h> 25 #include <iprt/alloca.h> 25 26 #include <iprt/string.h> 26 27 #include <iprt/err.h> 27 28 #if defined(RT_OS_WINDOWS) 29 # include <stdlib.h>30 # else28 #include "internal/magics.h" 29 30 #include <stdlib.h> 31 #if !defined(RT_OS_WINDOWS) 31 32 # include <unistd.h> 32 33 #endif 33 34 #include <string.h>35 36 34 #if defined(RT_OS_SOLARIS) 37 /* It's an implementation detail in Solaris, see 38 * http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libc/port/gen/getenv.c line 50. 35 __BEGIN_DECLS 36 extern char **environ; 37 __END_DECLS 38 #endif 39 40 /******************************************************************************* 41 * Defined Constants And Macros * 42 *******************************************************************************/ 43 /** Macro that unlocks the specified environment block. */ 44 #define RTENV_LOCK(pEnvInt) do { } while (0) 45 /** Macro that unlocks the specified environment block. */ 46 #define RTENV_UNLOCK(pEnvInt) do { } while (0) 47 48 49 /******************************************************************************* 50 * Structures and Typedefs * 51 *******************************************************************************/ 52 /** 53 * The internal representation of a (non-default) environment. 39 54 */ 40 extern char **environ; 41 #endif 42 43 struct RTENVINTERNAL 44 { 45 /* Array of environment variables. */ 46 char **apszEnv; 47 /* Count of variables in the array. */ 48 size_t cCount; 49 /* Capacity (real size) of the array. This includes space for the 50 * terminating NULL element (for compatibility with the C library), so 51 * that cCount <= cCapacity - 1. */ 52 size_t cCapacity; 53 }; 54 55 #define RTENV_GROW_SIZE 16 56 57 static int rtEnvCreate(struct RTENVINTERNAL **ppIntEnv, size_t cCapacity) 58 { 59 int rc; 60 55 typedef struct RTENVINTERNAL 56 { 57 /** Magic value . */ 58 uint32_t u32Magic; 59 /** Number of variables in the array. 60 * This does not include the terminating NULL entry. */ 61 size_t cVars; 62 /** Capacity (allocated size) of the array. 63 * This includes space for the terminating NULL element (for compatibility 64 * with the C library), so that c <= cCapacity - 1. */ 65 size_t cAllocated; 66 /** Array of environment variables. */ 67 char **papszEnv; 68 /** Array of environment variables in the process CP. 69 * This get (re-)constructed when RTEnvGetExecEnvP method is called. */ 70 char **papszEnvOtherCP; 71 } RTENVINTERNAL, *PRTENVINTERNAL; 72 73 /** The allocation granularity of the RTENVINTERNAL::papszEnv memory. */ 74 #define RTENV_GROW_SIZE 16 75 76 77 /** 78 * Internal worker that resolves the pointer to the default 79 * process environment. (environ) 80 * 81 * @returns Pointer to the default environment. 82 * This may be NULL. 83 */ 84 static const char * const *rtEnvDefault(void) 85 { 86 #ifdef RT_OS_DARWIN 87 return *(_NSGetEnviron()); 88 #elif defined(RT_OS_L4) 89 /* So far, our L4 libraries do not include environment support. */ 90 return NULL; 91 #else 92 return environ; 93 #endif 94 } 95 96 97 /** 98 * Internal worker that creates an environment handle with a specified capacity. 99 * 100 * @returns IPRT status code. 101 * @param ppIntEnv Where to store the result. 102 * @param cAllocated The initial array size. 103 */ 104 static int rtEnvCreate(PRTENVINTERNAL *ppIntEnv, size_t cAllocated) 105 { 61 106 /* 62 107 * Allocate environment handle. 63 108 */ 64 struct RTENVINTERNAL *pIntEnv = (struct RTENVINTERNAL *)RTMemAlloc(sizeof(struct RTENVINTERNAL));109 PRTENVINTERNAL pIntEnv = (PRTENVINTERNAL)RTMemAlloc(sizeof(*pIntEnv)); 65 110 if (pIntEnv) 66 111 { 67 cCapacity = (cCapacity + RTENV_GROW_SIZE - 1)68 / RTENV_GROW_SIZE * RTENV_GROW_SIZE;69 112 /* 70 113 * Pre-allocate the variable array. 71 114 */ 72 pIntEnv-> cCount = 0;73 pIntEnv-> cCapacity = cCapacity;74 pIntEnv-> apszEnv = (char **)RTMemAlloc(sizeof(pIntEnv->apszEnv[0]) * pIntEnv->cCapacity);75 if (pIntEnv->apszEnv)76 {77 /* add terminating NULL */78 pIntEnv->apszEnv[0] = NULL;115 pIntEnv->u32Magic = RTENV_MAGIC; 116 pIntEnv->papszEnvOtherCP = NULL; 117 pIntEnv->cVars = 0; 118 pIntEnv->cAllocated = RT_ALIGN_Z(RT_MAX(cAllocated, RTENV_GROW_SIZE), RTENV_GROW_SIZE); 119 pIntEnv->papszEnv = (char **)RTMemAllocZ(sizeof(pIntEnv->papszEnv[0]) * pIntEnv->cAllocated); 120 if (pIntEnv->papszEnv) 121 { 79 122 *ppIntEnv = pIntEnv; 80 123 return VINF_SUCCESS; 81 124 } 82 125 83 rc = VERR_NO_MEMORY;84 126 RTMemFree(pIntEnv); 85 127 } 128 129 return VERR_NO_MEMORY; 130 } 131 132 133 RTDECL(int) RTEnvCreate(PRTENV pEnv) 134 { 135 AssertPtrReturn(pEnv, VERR_INVALID_POINTER); 136 return rtEnvCreate(pEnv, RTENV_GROW_SIZE); 137 } 138 139 140 RTDECL(int) RTEnvDestroy(RTENV Env) 141 { 142 /* 143 * Ignore NIL_RTENV and validate input. 144 */ 145 if ( Env == NIL_RTENV 146 || Env == RTENV_DEFAULT) 147 return VINF_SUCCESS; 148 149 PRTENVINTERNAL pIntEnv = Env; 150 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE); 151 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE); 152 153 /* 154 * Do the cleanup. 155 */ 156 RTENV_LOCK(pIntEnv); 157 pIntEnv->u32Magic++; 158 size_t iVar = pIntEnv->cVars; 159 while (iVar-- > 0) 160 RTStrFree(pIntEnv->papszEnv[iVar]); 161 RTMemFree(pIntEnv->papszEnv); 162 pIntEnv->papszEnv = NULL; 163 164 if (pIntEnv->papszEnvOtherCP) 165 { 166 for (iVar = 0; pIntEnv->papszEnvOtherCP[iVar]; iVar++) 167 { 168 RTStrFree(pIntEnv->papszEnvOtherCP[iVar]); 169 pIntEnv->papszEnvOtherCP[iVar] = NULL; 170 } 171 RTMemFree(pIntEnv->papszEnvOtherCP); 172 pIntEnv->papszEnvOtherCP = NULL; 173 } 174 175 RTENV_UNLOCK(pIntEnv); 176 /*RTCritSectDelete(&pIntEnv->CritSect) */ 177 RTMemFree(pIntEnv); 178 179 return VINF_SUCCESS; 180 } 181 182 183 RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone) 184 { 185 /* 186 * Validate input and figure out how many variable to clone and where to get them. 187 */ 188 size_t cVars; 189 const char * const *papszEnv; 190 PRTENVINTERNAL pIntEnvToClone; 191 AssertPtrReturn(pEnv, VERR_INVALID_POINTER); 192 if (EnvToClone == RTENV_DEFAULT) 193 { 194 pIntEnvToClone = NULL; 195 papszEnv = rtEnvDefault(); 196 cVars = 0; 197 if (papszEnv) 198 while (papszEnv[cVars]) 199 cVars++; 200 } 86 201 else 87 rc = VERR_NO_MEMORY; 88 202 { 203 pIntEnvToClone = EnvToClone; 204 AssertPtrReturn(pIntEnvToClone, VERR_INVALID_HANDLE); 205 AssertReturn(pIntEnvToClone->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE); 206 RTENV_LOCK(pIntEnvToClone); 207 208 papszEnv = pIntEnvToClone->papszEnv; 209 cVars = pIntEnvToClone->cVars; 210 } 211 212 /* 213 * Create the duplicate. 214 */ 215 PRTENVINTERNAL pIntEnv; 216 int rc = rtEnvCreate(&pIntEnv, cVars + 1 /* NULL */); 217 if (RT_SUCCESS(rc)) 218 { 219 pIntEnv->cVars = cVars; 220 pIntEnv->papszEnv[pIntEnv->cVars] = NULL; 221 if (EnvToClone == RTENV_DEFAULT) 222 { 223 /* ASSUMES the default environment is in the current codepage. */ 224 for (size_t iVar = 0; iVar < cVars; iVar++) 225 { 226 int rc = RTStrCurrentCPToUtf8(&pIntEnv->papszEnv[iVar], papszEnv[iVar]); 227 if (RT_FAILURE(rc)) 228 { 229 pIntEnv->cVars = iVar; 230 RTEnvDestroy(pIntEnv); 231 return rc; 232 } 233 } 234 } 235 else 236 { 237 for (size_t iVar = 0; iVar < cVars; iVar++) 238 { 239 char *pszVar = RTStrDup(papszEnv[iVar]); 240 if (RT_UNLIKELY(!pszVar)) 241 { 242 RTENV_UNLOCK(pIntEnvToClone); 243 244 pIntEnv->cVars = iVar; 245 RTEnvDestroy(pIntEnv); 246 return rc; 247 } 248 pIntEnv->papszEnv[iVar] = pszVar; 249 } 250 } 251 252 /* done */ 253 *pEnv = pIntEnv; 254 } 255 256 if (pIntEnvToClone) 257 RTENV_UNLOCK(pIntEnvToClone); 89 258 return rc; 90 259 } 91 260 92 /** 93 * Creates an empty environment block. 94 * 95 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 96 * 97 * @param pEnv Where to store the handle of the environment block. 98 */ 99 RTDECL(int) RTEnvCreate(PRTENV pEnv) 100 { 101 if (pEnv == NULL) 102 return VERR_INVALID_POINTER; 103 104 return rtEnvCreate(pEnv, RTENV_GROW_SIZE); 105 } 106 107 /** 108 * Destroys an environment block. 109 * 110 * @returns IPRT status code. 111 * 112 * @param Env Handle of the environment block. 113 */ 114 RTDECL(int) RTEnvDestroy(RTENV Env) 115 { 116 struct RTENVINTERNAL *pIntEnv = Env; 117 118 if (pIntEnv == NULL) 119 return VERR_INVALID_HANDLE; 120 121 for (size_t i = 0; i < pIntEnv->cCount; ++i) 122 { 123 RTStrFree(pIntEnv->apszEnv[i]); 124 } 125 126 RTMemFree(pIntEnv->apszEnv); 127 RTMemFree(pIntEnv); 128 return VINF_SUCCESS; 129 } 130 131 /** 132 * Creates an environment block and fill it with variables from the given 133 * environment array. 134 * 135 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 136 * 137 * @param pEnv Where to store the handle of the environment block. 138 * @param apszEnv Pointer to the NULL-terminated array of environment 139 * variables. If NULL, the current process' environment 140 * will be cloned. 141 */ 142 RTDECL(int) RTEnvClone(PRTENV pEnv, char const *const *apszEnv) 143 { 144 #ifndef RT_OS_L4 /* So far, our L4 libraries do not include environment support. */ 145 if (apszEnv == NULL) 146 apszEnv = environ; 147 148 /* count the number of varialbes to clone */ 149 size_t cEnv = 0; 150 for (; apszEnv[cEnv]; ++cEnv) {} 151 #else 152 size_t cEnv = 0; 153 #endif 154 155 struct RTENVINTERNAL *pIntEnv; 156 157 int rc = rtEnvCreate(&pIntEnv, cEnv + 1 /* NULL */); 158 if (RT_FAILURE(rc)) 159 return rc; 160 161 #ifndef RT_OS_L4 162 for (size_t i = 0; i < cEnv; ++i) 163 { 164 char *pszVar = RTStrDup(environ[i]); 165 if (pszVar == NULL) 166 { 261 262 RTDECL(int) RTEnvPutEx(RTENV Env, const char *pszVarEqualValue) 263 { 264 int rc; 265 AssertPtrReturn(pszVarEqualValue, VERR_INVALID_POINTER); 266 const char *pszEq = strchr(pszVarEqualValue, '='); 267 if (!pszEq) 268 rc = RTEnvUnsetEx(Env, pszVarEqualValue); 269 else 270 { 271 /* 272 * Make a copy of the variable name so we can terminate it 273 * properly and then pass the request on to RTEnvSetEx. 274 */ 275 const char *pszValue = pszEq + 1; 276 277 size_t cchVar = pszEq - pszVarEqualValue; 278 Assert(cchVar < 1024); 279 char *pszVar = (char *)alloca(cchVar + 1); 280 memcpy(pszVar, pszVarEqualValue, cchVar); 281 pszVar[cchVar] = '\0'; 282 283 rc = RTEnvSetEx(Env, pszVar, pszValue); 284 } 285 return rc; 286 } 287 288 289 RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue) 290 { 291 AssertPtrReturn(pszVar, VERR_INVALID_POINTER); 292 AssertPtrReturn(*pszVar, VERR_INVALID_PARAMETER); 293 AssertPtrReturn(pszValue, VERR_INVALID_POINTER); 294 295 int rc; 296 if (Env == RTENV_DEFAULT) 297 { 298 /* 299 * Since RTEnvPut isn't UTF-8 clean and actually expects the strings 300 * to be in the current code page (codeset), we'll do the necessary 301 * conversions here. 302 */ 303 char *pszVarOtherCP; 304 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar); 305 if (RT_SUCCESS(rc)) 306 { 307 char *pszValueOtherCP; 308 rc = RTStrUtf8ToCurrentCP(&pszValueOtherCP, pszValue); 309 if (RT_SUCCESS(rc)) 310 { 311 rc = RTEnvSet(pszVarOtherCP, pszValueOtherCP); 312 RTStrFree(pszValueOtherCP); 313 } 314 RTStrFree(pszVarOtherCP); 315 } 316 } 317 else 318 { 319 PRTENVINTERNAL pIntEnv = Env; 320 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE); 321 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE); 322 323 /* 324 * Create the variable string. 325 */ 326 const size_t cchVar = strlen(pszVar); 327 const size_t cchValue = strlen(pszValue); 328 char *pszEntry = (char *)RTMemAlloc(cchVar + cchValue + 2); 329 if (pszEntry) 330 { 331 memcpy(pszEntry, pszVar, cchVar); 332 pszEntry[cchVar] = '='; 333 memcpy(&pszEntry[cchVar + 1], pszValue, cchValue + 1); 334 335 RTENV_LOCK(pIntEnv); 336 337 /* 338 * Find the location of the variable. (iVar = cVars if new) 339 */ 340 rc = VINF_SUCCESS; 341 size_t iVar; 342 for (iVar = 0; iVar < pIntEnv->cVars; iVar++) 343 if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar) 344 && pIntEnv->papszEnv[iVar][cchVar] == '=') 345 break; 346 if (iVar < pIntEnv->cVars) 347 { 348 /* 349 * Replace the current entry. Simple. 350 */ 351 RTMemFree(pIntEnv->papszEnv[iVar]); 352 pIntEnv->papszEnv[iVar] = pszEntry; 353 } 354 else 355 { 356 /* 357 * Adding a new variable. Resize the array if required 358 * and then insert the new value at the end. 359 */ 360 if (pIntEnv->cVars + 2 > pIntEnv->cAllocated) 361 { 362 void *pvNew = RTMemRealloc(pIntEnv->papszEnv, sizeof(char *) * (pIntEnv->cAllocated + RTENV_GROW_SIZE)); 363 if (!pvNew) 364 rc = VERR_NO_MEMORY; 365 else 366 { 367 pIntEnv->papszEnv = (char **)pvNew; 368 pIntEnv->cAllocated += RTENV_GROW_SIZE; 369 for (size_t iNewVar = pIntEnv->cVars; iNewVar < pIntEnv->cAllocated; iNewVar++) 370 pIntEnv->papszEnv[iNewVar] = NULL; 371 } 372 } 373 if (RT_SUCCESS(rc)) 374 { 375 pIntEnv->papszEnv[iVar] = pszEntry; 376 pIntEnv->papszEnv[iVar + 1] = NULL; /* this isn't really necessary, but doesn't hurt. */ 377 pIntEnv->cVars++; 378 Assert(pIntEnv->cVars == iVar + 1); 379 } 380 } 381 382 RTENV_UNLOCK(pIntEnv); 383 384 if (RT_FAILURE(rc)) 385 RTMemFree(pszEntry); 386 } 387 else 167 388 rc = VERR_NO_MEMORY; 168 break; 169 } 170 171 pIntEnv->apszEnv[i] = pszVar; 172 ++pIntEnv->cCount; 173 } 174 #endif 175 176 if (RT_SUCCESS(rc)) 177 { 178 /* add terminating NULL */ 179 pIntEnv->apszEnv[pIntEnv->cCount] = NULL; 180 *pEnv = pIntEnv; 181 return VINF_SUCCESS; 182 } 183 184 RTEnvDestroy(pIntEnv); 389 } 185 390 return rc; 186 391 } 187 392 188 static int rtEnvRemoveVars(struct RTENVINTERNAL *pIntEnv, size_t iFrom, size_t cVars) 189 { 190 AssertReturn (iFrom < pIntEnv->cCount, VERR_GENERAL_FAILURE); 191 AssertReturn (cVars <= pIntEnv->cCount, VERR_GENERAL_FAILURE); 192 AssertReturn (cVars > 0, VERR_GENERAL_FAILURE); 193 194 /* free variables */ 195 size_t iTo = iFrom + cVars - 1; 196 for (size_t i = iFrom; i <= iTo; ++i) 197 RTStrFree(pIntEnv->apszEnv[i]); 198 199 /* remove the hole */ 200 size_t cToMove = pIntEnv->cCount - iTo - 1; 201 if (cToMove) 202 memcpy(&pIntEnv->apszEnv[iFrom], &pIntEnv->apszEnv[iTo + 1], 203 sizeof(pIntEnv->apszEnv[0]) * cToMove); 204 205 pIntEnv->cCount -= cVars; 206 207 /// @todo resize pIntEnv->apszEnv to a multiply of RTENV_GROW_SIZE to keep 208 /// it compact 209 210 /* add terminating NULL */ 211 pIntEnv->apszEnv[pIntEnv->cCount] = NULL; 212 return VINF_SUCCESS; 213 } 214 215 static int rtEnvInsertVars(struct RTENVINTERNAL *pIntEnv, size_t iAt, size_t cVars) 216 { 217 AssertReturn (iAt <= pIntEnv->cCount, VERR_GENERAL_FAILURE); 393 394 RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar) 395 { 396 AssertPtrReturn(pszVar, VERR_INVALID_POINTER); 397 AssertPtrReturn(*pszVar, VERR_INVALID_PARAMETER); 218 398 219 399 int rc; 220 221 size_t cCapacity = (pIntEnv->cCount + cVars + 1 /* NULL */ + RTENV_GROW_SIZE - 1) 222 / RTENV_GROW_SIZE * RTENV_GROW_SIZE; 223 bool needAlloc = cCapacity != pIntEnv->cCapacity; 224 225 /* allocate a new variable array if needed */ 226 char **apszEnv = needAlloc ? (char **)RTMemAlloc(sizeof(apszEnv[0]) * cCapacity) 227 : pIntEnv->apszEnv; 228 if (apszEnv) 229 { 230 /* copy old variables */ 231 if (needAlloc && iAt) 232 memcpy (apszEnv, pIntEnv->apszEnv, sizeof(apszEnv[0]) * iAt); 233 if (iAt < pIntEnv->cCount) 234 memcpy (&apszEnv[iAt + cVars], &pIntEnv->apszEnv[iAt], 235 sizeof(apszEnv[0]) * pIntEnv->cCount - iAt); 236 /* initialize new variables with NULL */ 237 memset(&apszEnv[iAt], 0, sizeof(apszEnv[0]) * cVars); 238 /* replace the array */ 239 if (needAlloc) 240 { 241 RTMemFree(pIntEnv->apszEnv); 242 pIntEnv->apszEnv = apszEnv; 243 pIntEnv->cCapacity = cCapacity; 244 } 245 pIntEnv->cCount += cVars; 246 /* add terminating NULL */ 247 pIntEnv->apszEnv[pIntEnv->cCount] = NULL; 248 return VINF_SUCCESS; 400 if (Env == RTENV_DEFAULT) 401 { 402 /* 403 * Since RTEnvUnset isn't UTF-8 clean and actually expects the strings 404 * to be in the current code page (codeset), we'll do the necessary 405 * conversions here. 406 */ 407 char *pszVarOtherCP; 408 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar); 409 if (RT_SUCCESS(rc)) 410 { 411 rc = RTEnvUnset(pszVarOtherCP); 412 RTStrFree(pszVarOtherCP); 413 } 249 414 } 250 415 else 251 rc = VERR_NO_MEMORY; 252 416 { 417 PRTENVINTERNAL pIntEnv = Env; 418 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE); 419 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE); 420 421 RTENV_LOCK(pIntEnv); 422 423 /* 424 * Remove all variable by the given name. 425 */ 426 rc = VINF_ENV_VAR_NOT_FOUND; 427 const size_t cchVar = strlen(pszVar); 428 size_t iVar; 429 for (iVar = 0; iVar < pIntEnv->cVars; iVar++) 430 if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar) 431 && pIntEnv->papszEnv[iVar][cchVar] == '=') 432 { 433 RTMemFree(pIntEnv->papszEnv[iVar]); 434 pIntEnv->cVars--; 435 if (pIntEnv->cVars > 0) 436 pIntEnv->papszEnv[iVar] = pIntEnv->papszEnv[pIntEnv->cVars]; 437 pIntEnv->papszEnv[pIntEnv->cVars] = NULL; 438 rc = VINF_SUCCESS; 439 /* no break, there could be more. */ 440 } 441 442 RTENV_UNLOCK(pIntEnv); 443 } 253 444

