1 /*------------------------------------------------------------------------- 2 * 3 * win32env.c 4 * putenv() and unsetenv() for win32, which update both process environment 5 * and caches in (potentially multiple) C run-time library (CRT) versions. 6 * 7 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group 8 * Portions Copyright (c) 1994, Regents of the University of California 9 * 10 * 11 * IDENTIFICATION 12 * src/port/win32env.c 13 * 14 *------------------------------------------------------------------------- 15 */ 16 17 #include "c.h" 18 19 int 20 pgwin32_putenv(const char *envval) 21 { 22 char *envcpy; 23 char *cp; 24 typedef int (_cdecl * PUTENVPROC) (const char *); 25 static const char *const modulenames[] = { 26 "msvcrt", /* Visual Studio 6.0 / MinGW */ 27 "msvcrtd", 28 "msvcr70", /* Visual Studio 2002 */ 29 "msvcr70d", 30 "msvcr71", /* Visual Studio 2003 */ 31 "msvcr71d", 32 "msvcr80", /* Visual Studio 2005 */ 33 "msvcr80d", 34 "msvcr90", /* Visual Studio 2008 */ InOutBox(MidiWorker * p_midiWorker,GlobStore * p_globStore,int portCount,bool compactStyle,bool inOutVisible,const QString & p_name)35 "msvcr90d", 36 "msvcr100", /* Visual Studio 2010 */ 37 "msvcr100d", 38 "msvcr110", /* Visual Studio 2012 */ 39 "msvcr110d", 40 "msvcr120", /* Visual Studio 2013 */ 41 "msvcr120d", 42 "ucrtbase", /* Visual Studio 2015 and later */ 43 "ucrtbased", 44 NULL 45 }; 46 int i; 47 48 /* 49 * Update process environment, making this change visible to child 50 * processes and to CRTs initializing in the future. Do this before the 51 * _putenv() loop, for the benefit of any CRT that initializes during this 52 * pgwin32_putenv() execution, after the loop checks that CRT. 53 * 54 * Need a copy of the string so we can modify it. 55 */ 56 envcpy = strdup(envval); 57 if (!envcpy) 58 return -1; 59 cp = strchr(envcpy, '='); 60 if (cp == NULL) 61 { 62 free(envcpy); 63 return -1; 64 } 65 *cp = '\0'; 66 cp++; 67 if (strlen(cp)) 68 { 69 /* 70 * Only call SetEnvironmentVariable() when we are adding a variable, 71 * not when removing it. Calling it on both crashes on at least 72 * certain versions of MinGW. 73 */ 74 if (!SetEnvironmentVariable(envcpy, cp)) 75 { 76 free(envcpy); 77 return -1; 78 } 79 } 80 free(envcpy); 81 82 /* 83 * Each CRT has its own _putenv() symbol and copy of the environment. 84 * Update the environment in each CRT module currently loaded, so every 85 * third-party library sees this change regardless of the CRT it links 86 * against. Addresses within these modules may become invalid the moment 87 * we call FreeLibrary(), so don't cache them. 88 */ 89 for (i = 0; modulenames[i]; i++) 90 { 91 HMODULE hmodule = NULL; 92 BOOL res = GetModuleHandleEx(0, modulenames[i], &hmodule); 93 94 if (res != 0 && hmodule != NULL) 95 { 96 PUTENVPROC putenvFunc; 97 98 putenvFunc = (PUTENVPROC) GetProcAddress(hmodule, "_putenv"); 99 if (putenvFunc) 100 putenvFunc(envval); 101 FreeLibrary(hmodule); 102 } 103 } 104 105 /* 106 * Finally, update our "own" cache. This is redundant with the loop 107 * above, except when PostgreSQL itself links to a CRT not listed above. 108 * Ideally, the loop does visit all possible CRTs, making this redundant. 109 */ 110 return _putenv(envval); 111 } 112 113 void 114 pgwin32_unsetenv(const char *name) 115 { 116 char *envbuf; 117 118 envbuf = (char *) malloc(strlen(name) + 2); 119 if (!envbuf) 120 return; 121 122 sprintf(envbuf, "%s=", name); 123 pgwin32_putenv(envbuf); 124 free(envbuf); 125 } 126