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-2016, 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
pgwin32_putenv(const char * envval)20 pgwin32_putenv(const char *envval)
21 {
22 char *envcpy;
23 char *cp;
24
25 /*
26 * Each CRT has its own _putenv() symbol and copy of the environment.
27 * Update the environment in each CRT module currently loaded, so every
28 * third-party library sees this change regardless of the CRT it links
29 * against.
30 */
31 #ifdef _MSC_VER
32 typedef int (_cdecl * PUTENVPROC) (const char *);
33 static struct
34 {
35 char *modulename;
36 HMODULE hmodule;
37 PUTENVPROC putenvFunc;
38 } rtmodules[] =
39 {
40 {
41 "msvcrt", NULL, NULL
42 }, /* Visual Studio 6.0 / MinGW */
43 {
44 "msvcrtd", NULL, NULL
45 },
46 {
47 "msvcr70", NULL, NULL
48 }, /* Visual Studio 2002 */
49 {
50 "msvcr70d", NULL, NULL
51 },
52 {
53 "msvcr71", NULL, NULL
54 }, /* Visual Studio 2003 */
55 {
56 "msvcr71d", NULL, NULL
57 },
58 {
59 "msvcr80", NULL, NULL
60 }, /* Visual Studio 2005 */
61 {
62 "msvcr80d", NULL, NULL
63 },
64 {
65 "msvcr90", NULL, NULL
66 }, /* Visual Studio 2008 */
67 {
68 "msvcr90d", NULL, NULL
69 },
70 {
71 "msvcr100", NULL, NULL
72 }, /* Visual Studio 2010 */
73 {
74 "msvcr100d", NULL, NULL
75 },
76 {
77 "msvcr110", NULL, NULL
78 }, /* Visual Studio 2012 */
79 {
80 "msvcr110d", NULL, NULL
81 },
82 {
83 "msvcr120", NULL, NULL
84 }, /* Visual Studio 2013 */
85 {
86 "msvcr120d", NULL, NULL
87 },
88 {
89 "ucrtbase", NULL, NULL
90 }, /* Visual Studio 2015 and later */
91 {
92 "ucrtbased", NULL, NULL
93 },
94 {
95 NULL, NULL, NULL
96 }
97 };
98 int i;
99
100 for (i = 0; rtmodules[i].modulename; i++)
101 {
102 if (rtmodules[i].putenvFunc == NULL)
103 {
104 if (rtmodules[i].hmodule == NULL)
105 {
106 /* Not attempted before, so try to find this DLL */
107 rtmodules[i].hmodule = GetModuleHandle(rtmodules[i].modulename);
108 if (rtmodules[i].hmodule == NULL)
109 {
110 /*
111 * Set to INVALID_HANDLE_VALUE so we know we have tried
112 * this one before, and won't try again.
113 */
114 rtmodules[i].hmodule = INVALID_HANDLE_VALUE;
115 continue;
116 }
117 else
118 {
119 rtmodules[i].putenvFunc = (PUTENVPROC) GetProcAddress(rtmodules[i].hmodule, "_putenv");
120 if (rtmodules[i].putenvFunc == NULL)
121 {
122 rtmodules[i].hmodule = INVALID_HANDLE_VALUE;
123 continue;
124 }
125 }
126 }
127 else
128 {
129 /*
130 * Module loaded, but we did not find the function last time.
131 * We're not going to find it this time either...
132 */
133 continue;
134 }
135 }
136 /* At this point, putenvFunc is set or we have exited the loop */
137 rtmodules[i].putenvFunc(envval);
138 }
139 #endif /* _MSC_VER */
140
141 /*
142 * Update process environment, making this change visible to child
143 * processes and to CRTs initializing in the future.
144 *
145 * Need a copy of the string so we can modify it.
146 */
147 envcpy = strdup(envval);
148 if (!envcpy)
149 return -1;
150 cp = strchr(envcpy, '=');
151 if (cp == NULL)
152 {
153 free(envcpy);
154 return -1;
155 }
156 *cp = '\0';
157 cp++;
158 if (strlen(cp))
159 {
160 /*
161 * Only call SetEnvironmentVariable() when we are adding a variable,
162 * not when removing it. Calling it on both crashes on at least
163 * certain versions of MinGW.
164 */
165 if (!SetEnvironmentVariable(envcpy, cp))
166 {
167 free(envcpy);
168 return -1;
169 }
170 }
171 free(envcpy);
172
173 /* Finally, update our "own" cache */
174 return _putenv(envval);
175 }
176
177 void
pgwin32_unsetenv(const char * name)178 pgwin32_unsetenv(const char *name)
179 {
180 char *envbuf;
181
182 envbuf = (char *) malloc(strlen(name) + 2);
183 if (!envbuf)
184 return;
185
186 sprintf(envbuf, "%s=", name);
187 pgwin32_putenv(envbuf);
188 free(envbuf);
189 }
190