1
0
mirror of https://github.com/postgrespro/pg_probackup.git synced 2025-02-13 14:58:35 +02:00

[Issue #204] Make version check of remote agent more robust

This commit is contained in:
Grigory Smolkin 2020-05-12 22:14:29 +03:00
parent 497f5b2e9e
commit 2c711bd57b
5 changed files with 49 additions and 65 deletions

View File

@ -44,7 +44,7 @@ slurpFile(const char *datadir, const char *path, size_t *filesize, bool safe, fi
fullpath, strerror(errno));
}
if (fio_fstat(fd, &statbuf) < 0)
if (fio_stat(fullpath, &statbuf, true, location) < 0)
{
if (safe)
return NULL;

View File

@ -343,16 +343,8 @@ main(int argc, char *argv[])
else if (strcmp(argv[1], "ssh") == 0)
launch_ssh(argv);
#endif
else if (strcmp(argv[1], "agent") == 0 && argc > 2)
else if (strcmp(argv[1], "agent") == 0)
{
remote_agent = argv[2];
if (strcmp(remote_agent, PROGRAM_VERSION) != 0)
{
uint32 agent_version = parse_program_version(remote_agent);
elog(agent_version != AGENT_PROTOCOL_VERSION ? ERROR : WARNING,
"Agent version %s doesn't match master pg_probackup version %s",
PROGRAM_VERSION, remote_agent);
}
fio_communicate(STDIN_FILENO, STDOUT_FILENO);
return 0;
}
@ -528,8 +520,7 @@ main(int argc, char *argv[])
{
/* Ensure that backup_path is a path to a directory */
if (!S_ISDIR(st.st_mode))
elog(ERROR, "-B, --backup-path must be a path to directory. Inode: %lu. ST_MODE: %u",
st.st_ino, st.st_mode);
elog(ERROR, "-B, --backup-path must be a path to directory");
}
}
}

View File

@ -185,6 +185,19 @@ static ssize_t fio_write_all(int fd, void const* buf, size_t size)
return offs;
}
/* Get version of remote agent */
int fio_get_agent_version(void)
{
fio_header hdr;
hdr.cop = FIO_AGENT_VERSION;
hdr.size = 0;
IO_CHECK(fio_write_all(fio_stdout, &hdr, sizeof(hdr)), sizeof(hdr));
IO_CHECK(fio_read_all(fio_stdin, &hdr, sizeof(hdr)), sizeof(hdr));
return hdr.arg;
}
/* Open input stream. Remote file is fetched to the in-memory buffer and then accessed through Linux fmemopen */
FILE* fio_open_stream(char const* path, fio_location location)
{
@ -728,44 +741,6 @@ ssize_t fio_read(int fd, void* buf, size_t size)
}
}
/* Get information about stdio file */
int fio_ffstat(FILE* f, struct stat* st)
{
return fio_is_remote_file(f)
? fio_fstat(fio_fileno(f), st)
: fio_fstat(fileno(f), st);
}
/* Get information about file descriptor */
int fio_fstat(int fd, struct stat* st)
{
if (fio_is_remote_fd(fd))
{
fio_header hdr;
hdr.cop = FIO_FSTAT;
hdr.handle = fd & ~FIO_PIPE_MARKER;
hdr.size = 0;
IO_CHECK(fio_write_all(fio_stdout, &hdr, sizeof(hdr)), sizeof(hdr));
IO_CHECK(fio_read_all(fio_stdin, &hdr, sizeof(hdr)), sizeof(hdr));
Assert(hdr.cop == FIO_FSTAT);
IO_CHECK(fio_read_all(fio_stdin, st, sizeof(*st)), sizeof(*st));
if (hdr.arg != 0)
{
errno = hdr.arg;
return -1;
}
return 0;
}
else
{
return fstat(fd, st);
}
}
/* Get information about file */
int fio_stat(char const* path, struct stat* st, bool follow_symlink, fio_location location)
{
@ -2065,11 +2040,9 @@ void fio_communicate(int in, int out)
if (hdr.size != 0)
IO_CHECK(fio_write_all(out, buf, hdr.size), hdr.size);
break;
case FIO_FSTAT: /* Get information about opened file */
hdr.size = sizeof(st);
hdr.arg = fstat(fd[hdr.handle], &st) < 0 ? errno : 0;
case FIO_AGENT_VERSION:
hdr.arg = AGENT_PROTOCOL_VERSION;
IO_CHECK(fio_write_all(out, &hdr, sizeof(hdr)), sizeof(hdr));
IO_CHECK(fio_write_all(out, &st, sizeof(st)), sizeof(st));
break;
case FIO_STAT: /* Get information about file with specified path */
hdr.size = sizeof(st);

View File

@ -27,7 +27,6 @@ typedef enum
FIO_READ,
FIO_LOAD,
FIO_STAT,
FIO_FSTAT,
FIO_SEND,
FIO_ACCESS,
FIO_OPENDIR,
@ -47,6 +46,8 @@ typedef enum
/* messages for closing connection */
FIO_DISCONNECT,
FIO_DISCONNECTED,
/* message for compatibility check */
FIO_AGENT_VERSION
} fio_operations;
typedef enum
@ -79,6 +80,7 @@ extern fio_location MyLocation;
extern void fio_redirect(int in, int out, int err);
extern void fio_communicate(int in, int out);
extern int fio_get_agent_version(void);
extern FILE* fio_fopen(char const* name, char const* mode, fio_location location);
extern size_t fio_fwrite(FILE* f, void const* buf, size_t size);
extern ssize_t fio_fwrite_compressed(FILE* f, void const* buf, size_t size, int compress_alg);

View File

@ -111,6 +111,7 @@ bool launch_agent(void)
int outfd[2];
int infd[2];
int errfd[2];
int agent_version;
ssh_argc = 0;
#ifdef WIN32
@ -163,24 +164,24 @@ bool launch_agent(void)
}
}
if (needs_quotes(instance_config.remote.path) || needs_quotes(PROGRAM_NAME_FULL))
snprintf(cmd, sizeof(cmd), "\"%s\\%s\" agent %s",
instance_config.remote.path, probackup, PROGRAM_VERSION);
snprintf(cmd, sizeof(cmd), "\"%s\\%s\" agent",
instance_config.remote.path, probackup);
else
snprintf(cmd, sizeof(cmd), "%s\\%s agent %s",
instance_config.remote.path, probackup, PROGRAM_VERSION);
snprintf(cmd, sizeof(cmd), "%s\\%s agent",
instance_config.remote.path, probackup);
#else
if (needs_quotes(instance_config.remote.path) || needs_quotes(PROGRAM_NAME_FULL))
snprintf(cmd, sizeof(cmd), "\"%s/%s\" agent %s",
instance_config.remote.path, probackup, PROGRAM_VERSION);
snprintf(cmd, sizeof(cmd), "\"%s/%s\" agent",
instance_config.remote.path, probackup);
else
snprintf(cmd, sizeof(cmd), "%s/%s agent %s",
instance_config.remote.path, probackup, PROGRAM_VERSION);
snprintf(cmd, sizeof(cmd), "%s/%s agent",
instance_config.remote.path, probackup);
#endif
} else {
if (needs_quotes(PROGRAM_NAME_FULL))
snprintf(cmd, sizeof(cmd), "\"%s\" agent %s", PROGRAM_NAME_FULL, PROGRAM_VERSION);
snprintf(cmd, sizeof(cmd), "\"%s\" agent", PROGRAM_NAME_FULL);
else
snprintf(cmd, sizeof(cmd), "%s agent %s", PROGRAM_NAME_FULL, PROGRAM_VERSION);
snprintf(cmd, sizeof(cmd), "%s agent", PROGRAM_NAME_FULL);
}
#ifdef WIN32
@ -228,5 +229,22 @@ bool launch_agent(void)
fio_redirect(infd[0], outfd[1], errfd[0]); /* write to stdout */
}
/* Make sure that remote agent has the same version
* TODO: we must also check PG version and fork edition
*/
agent_version = fio_get_agent_version();
if (agent_version != AGENT_PROTOCOL_VERSION)
{
char agent_version_str[1024];
sprintf(agent_version_str, "%d.%d.%d",
agent_version / 10000,
(agent_version / 100) % 100,
agent_version % 100);
elog(ERROR, "Remote agent version %s does not match local program version %s",
agent_version_str, PROGRAM_VERSION);
}
return true;
}