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

Commit f06b1c5

Browse files
committed
pg_upgrade: Check version of target cluster binaries
This expands the binary validation in pg_upgrade with a version check per binary to ensure that the target cluster installation only contains binaries from the target version. In order to reduce duplication, validate_exec is exported from port.h and the local copy in pg_upgrade is removed. Author: Daniel Gustafsson <daniel@yesql.se> Discussion: https://www.postgresql.org/message-id/flat/9328.1552952117@sss.pgh.pa.us
1 parent 8af3c23 commit f06b1c5

File tree

3 files changed

+38
-54
lines changed

3 files changed

+38
-54
lines changed

src/bin/pg_upgrade/exec.c

+36-52
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111

1212
#include <fcntl.h>
1313

14+
#include "common/string.h"
1415
#include "pg_upgrade.h"
1516

1617
static void check_data_dir(ClusterInfo *cluster);
1718
static void check_bin_dir(ClusterInfo *cluster);
1819
static void get_bin_version(ClusterInfo *cluster);
19-
static void validate_exec(const char *dir, const char *cmdName);
20+
static void check_exec(const char *dir, const char *program);
2021

2122
#ifdef WIN32
2223
static int win32_check_directory_write_permissions(void);
@@ -375,9 +376,9 @@ check_bin_dir(ClusterInfo *cluster)
375376
report_status(PG_FATAL, "\"%s\" is not a directory\n",
376377
cluster->bindir);
377378

378-
validate_exec(cluster->bindir, "postgres");
379-
validate_exec(cluster->bindir, "pg_controldata");
380-
validate_exec(cluster->bindir, "pg_ctl");
379+
check_exec(cluster->bindir, "postgres");
380+
check_exec(cluster->bindir, "pg_controldata");
381+
check_exec(cluster->bindir, "pg_ctl");
381382

382383
/*
383384
* Fetch the binary version after checking for the existence of pg_ctl.
@@ -388,9 +389,9 @@ check_bin_dir(ClusterInfo *cluster)
388389

389390
/* pg_resetxlog has been renamed to pg_resetwal in version 10 */
390391
if (GET_MAJOR_VERSION(cluster->bin_version) <= 906)
391-
validate_exec(cluster->bindir, "pg_resetxlog");
392+
check_exec(cluster->bindir, "pg_resetxlog");
392393
else
393-
validate_exec(cluster->bindir, "pg_resetwal");
394+
check_exec(cluster->bindir, "pg_resetwal");
394395

395396
if (cluster == &new_cluster)
396397
{
@@ -399,63 +400,46 @@ check_bin_dir(ClusterInfo *cluster)
399400
* pg_dumpall are used to dump the old cluster, but must be of the
400401
* target version.
401402
*/
402-
validate_exec(cluster->bindir, "initdb");
403-
validate_exec(cluster->bindir, "pg_dump");
404-
validate_exec(cluster->bindir, "pg_dumpall");
405-
validate_exec(cluster->bindir, "pg_restore");
406-
validate_exec(cluster->bindir, "psql");
407-
validate_exec(cluster->bindir, "vacuumdb");
403+
check_exec(cluster->bindir, "initdb");
404+
check_exec(cluster->bindir, "pg_dump");
405+
check_exec(cluster->bindir, "pg_dumpall");
406+
check_exec(cluster->bindir, "pg_restore");
407+
check_exec(cluster->bindir, "psql");
408+
check_exec(cluster->bindir, "vacuumdb");
408409
}
409410
}
410411

411-
412-
/*
413-
* validate_exec()
414-
*
415-
* validate "path" as an executable file
416-
*/
417412
static void
418-
validate_exec(const char *dir, const char *cmdName)
413+
check_exec(const char *dir, const char *program)
419414
{
420-
char path[MAXPGPATH];
421-
struct stat buf;
415+
char path[MAXPGPATH];
416+
char line[MAXPGPATH];
417+
char cmd[MAXPGPATH];
418+
char versionstr[128];
419+
int ret;
422420

423-
snprintf(path, sizeof(path), "%s/%s", dir, cmdName);
421+
snprintf(path, sizeof(path), "%s/%s", dir, program);
424422

425-
#ifdef WIN32
426-
/* Windows requires a .exe suffix for stat() */
427-
if (strlen(path) <= strlen(EXE_EXT) ||
428-
pg_strcasecmp(path + strlen(path) - strlen(EXE_EXT), EXE_EXT) != 0)
429-
strlcat(path, EXE_EXT, sizeof(path));
430-
#endif
423+
ret = validate_exec(path);
431424

432-
/*
433-
* Ensure that the file exists and is a regular file.
434-
*/
435-
if (stat(path, &buf) < 0)
436-
pg_fatal("check for \"%s\" failed: %s\n",
437-
path, strerror(errno));
438-
else if (!S_ISREG(buf.st_mode))
425+
if (ret == -1)
439426
pg_fatal("check for \"%s\" failed: not a regular file\n",
440427
path);
441-
442-
/*
443-
* Ensure that the file is both executable and readable (required for
444-
* dynamic loading).
445-
*/
446-
#ifndef WIN32
447-
if (access(path, R_OK) != 0)
448-
#else
449-
if ((buf.st_mode & S_IRUSR) == 0)
450-
#endif
451-
pg_fatal("check for \"%s\" failed: cannot read file (permission denied)\n",
428+
else if (ret == -2)
429+
pg_fatal("check for \"%s\" failed: cannot execute (permission denied)\n",
452430
path);
453431

454-
#ifndef WIN32
455-
if (access(path, X_OK) != 0)
456-
#else
457-
if ((buf.st_mode & S_IXUSR) == 0)
458-
#endif
459-
pg_fatal("check for \"%s\" failed: cannot execute (permission denied)\n",
432+
snprintf(cmd, sizeof(cmd), "\"%s\" -V", path);
433+
434+
if (!pipe_read_line(cmd, line, sizeof(line)))
435+
pg_fatal("check for \"%s\" failed: cannot execute\n",
460436
path);
437+
438+
pg_strip_crlf(line);
439+
440+
snprintf(versionstr, sizeof(versionstr), "%s (PostgreSQL) " PG_VERSION, program);
441+
442+
if (strcmp(line, versionstr) != 0)
443+
pg_fatal("check for \"%s\" failed: incorrect version: found \"%s\", expected \"%s\"\n",
444+
path, line, versionstr);
461445
}

src/common/exec.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
#define getcwd(cwd,len) GetCurrentDirectory(len, cwd)
5050
#endif
5151

52-
static int validate_exec(const char *path);
5352
static int resolve_symlinks(char *path);
5453

5554
#ifdef WIN32
@@ -63,7 +62,7 @@ static BOOL GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser);
6362
* -1 if the regular file "path" does not exist or cannot be executed.
6463
* -2 if the file is otherwise valid but cannot be read.
6564
*/
66-
static int
65+
int
6766
validate_exec(const char *path)
6867
{
6968
struct stat buf;

src/include/port.h

+1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ extern void pgfnames_cleanup(char **filenames);
125125
extern void set_pglocale_pgservice(const char *argv0, const char *app);
126126

127127
/* Portable way to find and execute binaries (in exec.c) */
128+
extern int validate_exec(const char *path);
128129
extern int find_my_exec(const char *argv0, char *retpath);
129130
extern int find_other_exec(const char *argv0, const char *target,
130131
const char *versionstr, char *retpath);

0 commit comments

Comments
 (0)