mirror of
https://github.com/postgres/postgres.git
synced 2025-08-27 07:42:10 +03:00
Use setenv() in preference to putenv().
Since at least 2001 we've used putenv() and avoided setenv(), on the grounds that the latter was unportable and not in POSIX. However, POSIX added it that same year, and by now the situation has reversed: setenv() is probably more portable than putenv(), since POSIX now treats the latter as not being a core function. And setenv() has cleaner semantics too. So, let's reverse that old policy. This commit adds a simple src/port/ implementation of setenv() for any stragglers (we have one in the buildfarm, but I'd not be surprised if that code is never used in the field). More importantly, extend win32env.c to also support setenv(). Then, replace usages of putenv() with setenv(), and get rid of some ad-hoc implementations of setenv() wannabees. Also, adjust our src/port/ implementation of unsetenv() to follow the POSIX spec that it returns an error indicator, rather than returning void as per the ancient BSD convention. I don't feel a need to make all the call sites check for errors, but the portability stub ought to match real-world practice. Discussion: https://postgr.es/m/2065122.1609212051@sss.pgh.pa.us
This commit is contained in:
48
src/port/setenv.c
Normal file
48
src/port/setenv.c
Normal file
@@ -0,0 +1,48 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* setenv.c
|
||||
* setenv() emulation for machines without it
|
||||
*
|
||||
* Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/port/setenv.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "c.h"
|
||||
|
||||
|
||||
int
|
||||
setenv(const char *name, const char *value, int overwrite)
|
||||
{
|
||||
char *envstr;
|
||||
|
||||
/* Error conditions, per POSIX */
|
||||
if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL ||
|
||||
value == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* No work if variable exists and we're not to replace it */
|
||||
if (overwrite == 0 && getenv(name) != NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Add or replace the value using putenv(). This will leak memory if the
|
||||
* same variable is repeatedly redefined, but there's little we can do
|
||||
* about that when sitting atop putenv().
|
||||
*/
|
||||
envstr = (char *) malloc(strlen(name) + strlen(value) + 2);
|
||||
if (!envstr) /* not much we can do if no memory */
|
||||
return -1;
|
||||
|
||||
sprintf(envstr, "%s=%s", name, value);
|
||||
|
||||
return putenv(envstr);
|
||||
}
|
@@ -16,13 +16,20 @@
|
||||
#include "c.h"
|
||||
|
||||
|
||||
void
|
||||
int
|
||||
unsetenv(const char *name)
|
||||
{
|
||||
char *envstr;
|
||||
|
||||
/* Error conditions, per POSIX */
|
||||
if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (getenv(name) == NULL)
|
||||
return; /* no work */
|
||||
return 0; /* no work */
|
||||
|
||||
/*
|
||||
* The technique embodied here works if libc follows the Single Unix Spec
|
||||
@@ -40,11 +47,12 @@ unsetenv(const char *name)
|
||||
|
||||
envstr = (char *) malloc(strlen(name) + 2);
|
||||
if (!envstr) /* not much we can do if no memory */
|
||||
return;
|
||||
return -1;
|
||||
|
||||
/* Override the existing setting by forcibly defining the var */
|
||||
sprintf(envstr, "%s=", name);
|
||||
putenv(envstr);
|
||||
if (putenv(envstr))
|
||||
return -1;
|
||||
|
||||
/* Now we can clobber the variable definition this way: */
|
||||
strcpy(envstr, "=");
|
||||
@@ -53,5 +61,5 @@ unsetenv(const char *name)
|
||||
* This last putenv cleans up if we have multiple zero-length names as a
|
||||
* result of unsetting multiple things.
|
||||
*/
|
||||
putenv(envstr);
|
||||
return putenv(envstr);
|
||||
}
|
||||
|
@@ -1,8 +1,10 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* win32env.c
|
||||
* putenv() and unsetenv() for win32, which update both process environment
|
||||
* and caches in (potentially multiple) C run-time library (CRT) versions.
|
||||
* putenv(), setenv(), and unsetenv() for win32.
|
||||
*
|
||||
* These functions update both the process environment and caches in
|
||||
* (potentially multiple) C run-time library (CRT) versions.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
@@ -16,6 +18,11 @@
|
||||
|
||||
#include "c.h"
|
||||
|
||||
|
||||
/*
|
||||
* Note that unlike POSIX putenv(), this doesn't use the passed-in string
|
||||
* as permanent storage.
|
||||
*/
|
||||
int
|
||||
pgwin32_putenv(const char *envval)
|
||||
{
|
||||
@@ -64,7 +71,7 @@ pgwin32_putenv(const char *envval)
|
||||
}
|
||||
*cp = '\0';
|
||||
cp++;
|
||||
if (strlen(cp))
|
||||
if (*cp)
|
||||
{
|
||||
/*
|
||||
* Only call SetEnvironmentVariable() when we are adding a variable,
|
||||
@@ -110,16 +117,47 @@ pgwin32_putenv(const char *envval)
|
||||
return _putenv(envval);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
pgwin32_setenv(const char *name, const char *value, int overwrite)
|
||||
{
|
||||
int res;
|
||||
char *envstr;
|
||||
|
||||
/* Error conditions, per POSIX */
|
||||
if (name == NULL || name[0] == '\0' || strchr(name, '=') != NULL ||
|
||||
value == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* No work if variable exists and we're not to replace it */
|
||||
if (overwrite == 0 && getenv(name) != NULL)
|
||||
return 0;
|
||||
|
||||
envstr = (char *) malloc(strlen(name) + strlen(value) + 2);
|
||||
if (!envstr) /* not much we can do if no memory */
|
||||
return -1;
|
||||
|
||||
sprintf(envstr, "%s=%s", name, value);
|
||||
|
||||
res = pgwin32_putenv(envstr);
|
||||
free(envstr);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
pgwin32_unsetenv(const char *name)
|
||||
{
|
||||
int res;
|
||||
char *envbuf;
|
||||
|
||||
envbuf = (char *) malloc(strlen(name) + 2);
|
||||
if (!envbuf)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
sprintf(envbuf, "%s=", name);
|
||||
pgwin32_putenv(envbuf);
|
||||
res = pgwin32_putenv(envbuf);
|
||||
free(envbuf);
|
||||
return res;
|
||||
}
|
||||
|
Reference in New Issue
Block a user