PostgreSQL Source Code  git master
win32env.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * win32env.c
4  * putenv(), setenv(), and unsetenv() for win32.
5  *
6  * These functions update both the process environment and caches in
7  * (potentially multiple) C run-time library (CRT) versions.
8  *
9  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
10  * Portions Copyright (c) 1994, Regents of the University of California
11  *
12  *
13  * IDENTIFICATION
14  * src/port/win32env.c
15  *
16  *-------------------------------------------------------------------------
17  */
18 
19 #include "c.h"
20 
21 
22 /*
23  * Note that unlike POSIX putenv(), this doesn't use the passed-in string
24  * as permanent storage.
25  */
26 int
27 pgwin32_putenv(const char *envval)
28 {
29  char *envcpy;
30  char *cp;
31  typedef int (_cdecl * PUTENVPROC) (const char *);
32  static const char *const modulenames[] = {
33  "msvcrt", /* Visual Studio 6.0 / MinGW */
34  "msvcrtd",
35  "msvcr70", /* Visual Studio 2002 */
36  "msvcr70d",
37  "msvcr71", /* Visual Studio 2003 */
38  "msvcr71d",
39  "msvcr80", /* Visual Studio 2005 */
40  "msvcr80d",
41  "msvcr90", /* Visual Studio 2008 */
42  "msvcr90d",
43  "msvcr100", /* Visual Studio 2010 */
44  "msvcr100d",
45  "msvcr110", /* Visual Studio 2012 */
46  "msvcr110d",
47  "msvcr120", /* Visual Studio 2013 */
48  "msvcr120d",
49  "ucrtbase", /* Visual Studio 2015 and later */
50  "ucrtbased",
51  NULL
52  };
53  int i;
54 
55  /*
56  * Update process environment, making this change visible to child
57  * processes and to CRTs initializing in the future. Do this before the
58  * _putenv() loop, for the benefit of any CRT that initializes during this
59  * pgwin32_putenv() execution, after the loop checks that CRT.
60  *
61  * Need a copy of the string so we can modify it.
62  */
63  envcpy = strdup(envval);
64  if (!envcpy)
65  return -1;
66  cp = strchr(envcpy, '=');
67  if (cp == NULL)
68  {
69  free(envcpy);
70  return -1;
71  }
72  *cp = '\0';
73  cp++;
74  if (*cp)
75  {
76  /*
77  * Only call SetEnvironmentVariable() when we are adding a variable,
78  * not when removing it. Calling it on both crashes on at least
79  * certain versions of MinGW.
80  */
81  if (!SetEnvironmentVariable(envcpy, cp))
82  {
83  free(envcpy);
84  return -1;
85  }
86  }
87  free(envcpy);
88 
89  /*
90  * Each CRT has its own _putenv() symbol and copy of the environment.
91  * Update the environment in each CRT module currently loaded, so every
92  * third-party library sees this change regardless of the CRT it links
93  * against. Addresses within these modules may become invalid the moment
94  * we call FreeLibrary(), so don't cache them.
95  */
96  for (i = 0; modulenames[i]; i++)
97  {
98  HMODULE hmodule = NULL;
99  BOOL res = GetModuleHandleEx(0, modulenames[i], &hmodule);
100 
101  if (res != 0 && hmodule != NULL)
102  {
103  PUTENVPROC putenvFunc;
104 
105  putenvFunc = (PUTENVPROC) (pg_funcptr_t) GetProcAddress(hmodule, "_putenv");
106  if (putenvFunc)
107  putenvFunc(envval);
108  FreeLibrary(hmodule);
109  }
110  }
111 
112  /*
113  * Finally, update our "own" cache. This is redundant with the loop
114  * above, except when PostgreSQL itself links to a CRT not listed above.
115  * Ideally, the loop does visit all possible CRTs, making this redundant.
116  */
117  return _putenv(envval);
118 }
119 
120 int
121 pgwin32_setenv(const char *name, const char *value, int overwrite)
122 {
123  int res;
124  char *envstr;
125 
126  /* Error conditions, per POSIX */
127  if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL ||
128  value == NULL)
129  {
130  errno = EINVAL;
131  return -1;
132  }
133 
134  /* No work if variable exists and we're not to replace it */
135  if (overwrite == 0 && getenv(name) != NULL)
136  return 0;
137 
138  envstr = (char *) malloc(strlen(name) + strlen(value) + 2);
139  if (!envstr) /* not much we can do if no memory */
140  return -1;
141 
142  sprintf(envstr, "%s=%s", name, value);
143 
144  res = pgwin32_putenv(envstr);
145  free(envstr);
146  return res;
147 }
148 
149 int
150 pgwin32_unsetenv(const char *name)
151 {
152  int res;
153  char *envbuf;
154 
155  envbuf = (char *) malloc(strlen(name) + 2);
156  if (!envbuf)
157  return -1;
158 
159  sprintf(envbuf, "%s=", name);
160  res = pgwin32_putenv(envbuf);
161  free(envbuf);
162  return res;
163 }
void(* pg_funcptr_t)(void)
Definition: c.h:407
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
static struct @160 value
int i
Definition: isn.c:72
#define sprintf
Definition: port.h:240
static void overwrite(PGconn *conn, Oid lobjId, int start, int len)
Definition: testlo.c:108
const char * name
int pgwin32_unsetenv(const char *name)
Definition: win32env.c:150
int pgwin32_putenv(const char *envval)
Definition: win32env.c:27
int pgwin32_setenv(const char *name, const char *value, int overwrite)
Definition: win32env.c:121