Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6c19bd9

Browse files
committed
Allow pg_upgrade to honor libpq environment variables. Add 'local'
checks for PGHOST and PGHOSTADDR.
1 parent 78b66cf commit 6c19bd9

File tree

7 files changed

+141
-130
lines changed

7 files changed

+141
-130
lines changed

contrib/pg_upgrade/controldata.c

+18-57
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
#include <ctype.h>
1313

14-
static void putenv2(const char *var, const char *val);
15-
1614
/*
1715
* get_control_data()
1816
*
@@ -85,21 +83,21 @@ get_control_data(ClusterInfo *cluster, bool live_check)
8583
if (getenv("LC_MESSAGES"))
8684
lc_messages = pg_strdup(getenv("LC_MESSAGES"));
8785

88-
putenv2("LC_COLLATE", NULL);
89-
putenv2("LC_CTYPE", NULL);
90-
putenv2("LC_MONETARY", NULL);
91-
putenv2("LC_NUMERIC", NULL);
92-
putenv2("LC_TIME", NULL);
93-
putenv2("LANG",
86+
pg_putenv("LC_COLLATE", NULL);
87+
pg_putenv("LC_CTYPE", NULL);
88+
pg_putenv("LC_MONETARY", NULL);
89+
pg_putenv("LC_NUMERIC", NULL);
90+
pg_putenv("LC_TIME", NULL);
91+
pg_putenv("LANG",
9492
#ifndef WIN32
9593
NULL);
9694
#else
9795
/* On Windows the default locale cannot be English, so force it */
9896
"en");
9997
#endif
100-
putenv2("LANGUAGE", NULL);
101-
putenv2("LC_ALL", NULL);
102-
putenv2("LC_MESSAGES", "C");
98+
pg_putenv("LANGUAGE", NULL);
99+
pg_putenv("LC_ALL", NULL);
100+
pg_putenv("LC_MESSAGES", "C");
103101

104102
snprintf(cmd, sizeof(cmd), SYSTEMQUOTE "\"%s/%s \"%s\"" SYSTEMQUOTE,
105103
cluster->bindir,
@@ -374,15 +372,15 @@ get_control_data(ClusterInfo *cluster, bool live_check)
374372
/*
375373
* Restore environment variables
376374
*/
377-
putenv2("LC_COLLATE", lc_collate);
378-
putenv2("LC_CTYPE", lc_ctype);
379-
putenv2("LC_MONETARY", lc_monetary);
380-
putenv2("LC_NUMERIC", lc_numeric);
381-
putenv2("LC_TIME", lc_time);
382-
putenv2("LANG", lang);
383-
putenv2("LANGUAGE", language);
384-
putenv2("LC_ALL", lc_all);
385-
putenv2("LC_MESSAGES", lc_messages);
375+
pg_putenv("LC_COLLATE", lc_collate);
376+
pg_putenv("LC_CTYPE", lc_ctype);
377+
pg_putenv("LC_MONETARY", lc_monetary);
378+
pg_putenv("LC_NUMERIC", lc_numeric);
379+
pg_putenv("LC_TIME", lc_time);
380+
pg_putenv("LANG", lang);
381+
pg_putenv("LANGUAGE", language);
382+
pg_putenv("LC_ALL", lc_all);
383+
pg_putenv("LC_MESSAGES", lc_messages);
386384

387385
pg_free(lc_collate);
388386
pg_free(lc_ctype);
@@ -529,40 +527,3 @@ rename_old_pg_control(void)
529527
pg_log(PG_FATAL, "Unable to rename %s to %s.\n", old_path, new_path);
530528
check_ok();
531529
}
532-
533-
534-
/*
535-
* putenv2()
536-
*
537-
* This is like putenv(), but takes two arguments.
538-
* It also does unsetenv() if val is NULL.
539-
*/
540-
static void
541-
putenv2(const char *var, const char *val)
542-
{
543-
if (val)
544-
{
545-
#ifndef WIN32
546-
char *envstr = (char *) pg_malloc(strlen(var) +
547-
strlen(val) + 2);
548-
549-
sprintf(envstr, "%s=%s", var, val);
550-
putenv(envstr);
551-
552-
/*
553-
* Do not free envstr because it becomes part of the environment on
554-
* some operating systems. See port/unsetenv.c::unsetenv.
555-
*/
556-
#else
557-
SetEnvironmentVariableA(var, val);
558-
#endif
559-
}
560-
else
561-
{
562-
#ifndef WIN32
563-
unsetenv(var);
564-
#else
565-
SetEnvironmentVariableA(var, "");
566-
#endif
567-
}
568-
}

contrib/pg_upgrade/option.c

+31-24
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,24 @@ parseCommandLine(int argc, char *argv[])
5353
};
5454
int option; /* Command line option */
5555
int optindex = 0; /* used by getopt_long */
56-
int user_id;
56+
int os_user_effective_id;
5757

58-
if (getenv("PGUSER"))
59-
{
60-
pg_free(os_info.user);
61-
os_info.user = pg_strdup(getenv("PGUSER"));
62-
}
58+
user_opts.transfer_mode = TRANSFER_MODE_COPY;
6359

6460
os_info.progname = get_progname(argv[0]);
61+
62+
/* Process libpq env. variables; load values here for usage() output */
6563
old_cluster.port = getenv("PGPORT") ? atoi(getenv("PGPORT")) : DEF_PGPORT;
6664
new_cluster.port = getenv("PGPORT") ? atoi(getenv("PGPORT")) : DEF_PGPORT;
67-
/* must save value, getenv()'s pointer is not stable */
6865

69-
user_opts.transfer_mode = TRANSFER_MODE_COPY;
70-
71-
/* user lookup and 'root' test must be split because of usage() */
72-
user_id = get_user_info(&os_info.user);
66+
os_user_effective_id = get_user_info(&os_info.user);
67+
/* we override just the database user name; we got the OS id above */
68+
if (getenv("PGUSER"))
69+
{
70+
pg_free(os_info.user);
71+
/* must save value, getenv()'s pointer is not stable */
72+
os_info.user = pg_strdup(getenv("PGUSER"));
73+
}
7374

7475
if (argc > 1)
7576
{
@@ -86,7 +87,8 @@ parseCommandLine(int argc, char *argv[])
8687
}
8788
}
8889

89-
if (user_id == 0)
90+
/* Allow help and version to be run as root, so do the test here. */
91+
if (os_user_effective_id == 0)
9092
pg_log(PG_FATAL, "%s: cannot be run as root\n", os_info.progname);
9193

9294
getcwd(os_info.cwd, MAXPGPATH);
@@ -96,14 +98,6 @@ parseCommandLine(int argc, char *argv[])
9698
{
9799
switch (option)
98100
{
99-
case 'd':
100-
old_cluster.pgdata = pg_strdup(optarg);
101-
break;
102-
103-
case 'D':
104-
new_cluster.pgdata = pg_strdup(optarg);
105-
break;
106-
107101
case 'b':
108102
old_cluster.bindir = pg_strdup(optarg);
109103
break;
@@ -116,6 +110,14 @@ parseCommandLine(int argc, char *argv[])
116110
user_opts.check = true;
117111
break;
118112

113+
case 'd':
114+
old_cluster.pgdata = pg_strdup(optarg);
115+
break;
116+
117+
case 'D':
118+
new_cluster.pgdata = pg_strdup(optarg);
119+
break;
120+
119121
case 'g':
120122
pg_log(PG_REPORT, "Running in debug mode\n");
121123
log_opts.debug = true;
@@ -156,6 +158,11 @@ parseCommandLine(int argc, char *argv[])
156158
case 'u':
157159
pg_free(os_info.user);
158160
os_info.user = pg_strdup(optarg);
161+
/*
162+
* Push the user name into the environment so pre-9.1
163+
* pg_ctl/libpq uses it.
164+
*/
165+
pg_putenv("PGUSER", os_info.user);
159166
break;
160167

161168
case 'v':
@@ -197,14 +204,14 @@ parseCommandLine(int argc, char *argv[])
197204
}
198205

199206
/* Get values from env if not already set */
200-
validateDirectoryOption(&old_cluster.pgdata, "OLDDATADIR", "-d",
201-
"old cluster data resides");
202-
validateDirectoryOption(&new_cluster.pgdata, "NEWDATADIR", "-D",
203-
"new cluster data resides");
204207
validateDirectoryOption(&old_cluster.bindir, "OLDBINDIR", "-b",
205208
"old cluster binaries reside");
206209
validateDirectoryOption(&new_cluster.bindir, "NEWBINDIR", "-B",
207210
"new cluster binaries reside");
211+
validateDirectoryOption(&old_cluster.pgdata, "OLDDATADIR", "-d",
212+
"old cluster data resides");
213+
validateDirectoryOption(&new_cluster.pgdata, "NEWDATADIR", "-D",
214+
"new cluster data resides");
208215

209216
get_pkglibdirs();
210217
}

contrib/pg_upgrade/pg_upgrade.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ setup(char *argv0, bool live_check)
149149
* make sure the user has a clean environment, otherwise, we may confuse
150150
* libpq when we connect to one (or both) of the servers.
151151
*/
152-
check_for_libpq_envvars();
152+
check_pghost_envvar();
153153

154154
verify_directories();
155155

contrib/pg_upgrade/pg_upgrade.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ PGresult *executeQueryOrDie(PGconn *conn, const char *fmt,...);
361361
void start_postmaster(ClusterInfo *cluster);
362362
void stop_postmaster(bool fast);
363363
uint32 get_major_server_version(ClusterInfo *cluster);
364-
void check_for_libpq_envvars(void);
364+
void check_pghost_envvar(void);
365365

366366

367367
/* util.c */
@@ -378,6 +378,7 @@ void *pg_malloc(int size);
378378
void pg_free(void *ptr);
379379
const char *getErrorText(int errNum);
380380
unsigned int str2uint(const char *str);
381+
void pg_putenv(const char *var, const char *val);
381382

382383

383384
/* version.c */

contrib/pg_upgrade/server.c

+25-28
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ start_postmaster(ClusterInfo *cluster)
145145
char cmd[MAXPGPATH];
146146
PGconn *conn;
147147
bool exit_hook_registered = false;
148+
int pg_ctl_return = 0;
148149
#ifndef WIN32
149150
char *output_filename = log_opts.filename;
150151
#else
@@ -183,7 +184,11 @@ start_postmaster(ClusterInfo *cluster)
183184
"-c autovacuum=off -c autovacuum_freeze_max_age=2000000000",
184185
log_opts.filename);
185186

186-
exec_prog(true, "%s", cmd);
187+
/*
188+
* Don't throw an error right away, let connecting throw the error
189+
* because it might supply a reason for the failure.
190+
*/
191+
pg_ctl_return = exec_prog(false, "%s", cmd);
187192

188193
/* Check to see if we can connect to the server; if not, report it. */
189194
if ((conn = get_db_conn(cluster, "template1")) == NULL ||
@@ -198,6 +203,11 @@ start_postmaster(ClusterInfo *cluster)
198203
}
199204
PQfinish(conn);
200205

206+
/* If the connection didn't fail, fail now */
207+
if (pg_ctl_return != 0)
208+
pg_log(PG_FATAL, "pg_ctl failed to start the %s server\n",
209+
CLUSTER_NAME(cluster));
210+
201211
os_info.running_cluster = cluster;
202212
}
203213

@@ -241,50 +251,37 @@ stop_postmaster(bool fast)
241251

242252

243253
/*
244-
* check_for_libpq_envvars()
254+
* check_pghost_envvar()
245255
*
246-
* tests whether any libpq environment variables are set.
247-
* Since pg_upgrade connects to both the old and the new server,
248-
* it is potentially dangerous to have any of these set.
249-
*
250-
* If any are found, will log them and cancel.
256+
* Tests that PGHOST does not point to a non-local server
251257
*/
252258
void
253-
check_for_libpq_envvars(void)
259+
check_pghost_envvar(void)
254260
{
255261
PQconninfoOption *option;
256262
PQconninfoOption *start;
257-
bool found = false;
258263

259264
/* Get valid libpq env vars from the PQconndefaults function */
260265

261266
start = PQconndefaults();
262267

263268
for (option = start; option->keyword != NULL; option++)
264269
{
265-
if (option->envvar)
270+
if (option->envvar && (strcmp(option->envvar, "PGHOST") == 0 ||
271+
strcmp(option->envvar, "PGHOSTADDR") == 0))
266272
{
267-
const char *value;
268-
269-
/* This allows us to see error messages in the local encoding */
270-
if (strcmp(option->envvar, "PGCLIENTENCODING") == 0)
271-
continue;
272-
273-
value = getenv(option->envvar);
274-
if (value && strlen(value) > 0)
275-
{
276-
found = true;
277-
278-
pg_log(PG_WARNING,
279-
"libpq env var %-20s is currently set to: %s\n", option->envvar, value);
280-
}
273+
const char *value = getenv(option->envvar);
274+
275+
if (value && strlen(value) > 0 &&
276+
/* check for 'local' host values */
277+
(strcmp(value, "localhost") != 0 && strcmp(value, "127.0.0.1") != 0 &&
278+
strcmp(value, "::1") != 0 && value[0] != '/'))
279+
pg_log(PG_FATAL,
280+
"libpq environment variable %s has a non-local server value: %s\n",
281+
option->envvar, value);
281282
}
282283
}
283284

284285
/* Free the memory that libpq allocated on our behalf */
285286
PQconninfoFree(start);
286-
287-
if (found)
288-
pg_log(PG_FATAL,
289-
"libpq env vars have been found and listed above, please unset them for pg_upgrade\n");
290287
}

contrib/pg_upgrade/util.c

+38
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,41 @@ str2uint(const char *str)
244244
{
245245
return strtoul(str, NULL, 10);
246246
}
247+
248+
249+
/*
250+
* pg_putenv()
251+
*
252+
* This is like putenv(), but takes two arguments.
253+
* It also does unsetenv() if val is NULL.
254+
*/
255+
void
256+
pg_putenv(const char *var, const char *val)
257+
{
258+
if (val)
259+
{
260+
#ifndef WIN32
261+
char *envstr = (char *) pg_malloc(strlen(var) +
262+
strlen(val) + 2);
263+
264+
sprintf(envstr, "%s=%s", var, val);
265+
putenv(envstr);
266+
267+
/*
268+
* Do not free envstr because it becomes part of the environment on
269+
* some operating systems. See port/unsetenv.c::unsetenv.
270+
*/
271+
#else
272+
SetEnvironmentVariableA(var, val);
273+
#endif
274+
}
275+
else
276+
{
277+
#ifndef WIN32
278+
unsetenv(var);
279+
#else
280+
SetEnvironmentVariableA(var, "");
281+
#endif
282+
}
283+
}
284+

0 commit comments

Comments
 (0)