mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-01-18 04:58:51 +02:00
Fix archive-push/archive-get when PGDATA is symlinked.
Commit 7168e074 tried to use cwd() as PGDATA but this would disagree with the path configured in pgBackRest if PGDATA was symlinked. If cwd() does not match the pgBackRest path then chdir() to the path and make sure the next cwd() matches the result from the first call.
This commit is contained in:
parent
8c840c28a6
commit
0194a98671
@ -15,6 +15,17 @@
|
||||
<release date="XXXX-XX-XX" version="2.20dev" title="UNDER DEVELOPMENT">
|
||||
<release-core-list>
|
||||
<release-bug-list>
|
||||
<release-item>
|
||||
<release-item-contributor-list>
|
||||
<release-item-ideator id="stephen.frost"/>
|
||||
<release-item-ideator id="milosz.suchy"/>
|
||||
</release-item-contributor-list>
|
||||
|
||||
<p>Fix archive-push/archive-get when <path>PGDATA</path> is symlinked.</p>
|
||||
|
||||
<p>These commands tried to use <code>cwd()</code> as <path>PGDATA</path> but this would disagree with the path configured in pgBackRest if <path>PGDATA</path> was symlinked. If <code>cwd()</code> does not match the <backrest/> path then <code>chdir()</code> to the path and make sure the next <code>cwd()</code> matches the result from the first call.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
<p>Fix reference list when <file>backup.info</file> is reconstructed in <cmd>expire</cmd> command.</p>
|
||||
|
||||
@ -7809,6 +7820,11 @@
|
||||
<contributor-id type="github">M1hacka</contributor-id>
|
||||
</contributor>
|
||||
|
||||
<contributor id="milosz.suchy">
|
||||
<contributor-name-display>Milosz Suchy</contributor-name-display>
|
||||
<contributor-id type="github">Yuxael</contributor-id>
|
||||
</contributor>
|
||||
|
||||
<contributor id="mohamad.el.rifai">
|
||||
<contributor-name-display>Mohamad El-Rifai</contributor-name-display>
|
||||
<contributor-id type="github">melrifa1</contributor-id>
|
||||
|
@ -229,25 +229,56 @@ walIsPartial(const String *walSegment)
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Generates the location of the wal directory using either an absolute path or cwd() and a relative path
|
||||
Generates the location of the wal directory using a relative wal path and the supplied pg path
|
||||
***********************************************************************************************************************************/
|
||||
String *
|
||||
walPath(const String *walFile)
|
||||
walPath(const String *walFile, const String *pgPath, const String *command)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(STRING, walFile);
|
||||
FUNCTION_LOG_PARAM(STRING, pgPath);
|
||||
FUNCTION_LOG_PARAM(STRING, command);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(walFile != NULL);
|
||||
ASSERT(command != NULL);
|
||||
|
||||
String *result = NULL;
|
||||
|
||||
if (!strBeginsWithZ(walFile, "/"))
|
||||
{
|
||||
char currentWorkDir[4096];
|
||||
// Error if walFile has a relative path and pgPath is not set
|
||||
if (pgPath == NULL)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionRequiredError,
|
||||
"option '" CFGOPT_PG1_PATH "' must be specified when relative wal paths are used\n"
|
||||
"HINT: is %%f passed to %s instead of %%p?\n"
|
||||
"HINT: PostgreSQL may pass relative paths even with %%p depending on the environment.",
|
||||
strPtr(command));
|
||||
}
|
||||
|
||||
// Get the working directory
|
||||
char currentWorkDir[4096];
|
||||
THROW_ON_SYS_ERROR(getcwd(currentWorkDir, sizeof(currentWorkDir)) == NULL, FormatError, "unable to get cwd");
|
||||
result = strNewFmt("%s/%s", strcmp(currentWorkDir, "/") != 0 ? currentWorkDir : "", strPtr(walFile));
|
||||
|
||||
// Check if the working directory is the same as pgPath
|
||||
if (!strEqZ(pgPath, currentWorkDir))
|
||||
{
|
||||
// If not we'll change the working directory to pgPath and see if that equals the working directory we got called with
|
||||
THROW_ON_SYS_ERROR_FMT(chdir(strPtr(pgPath)) != 0, PathMissingError, "unable to chdir() to '%s'", strPtr(pgPath));
|
||||
|
||||
// Get the new working directory
|
||||
char newWorkDir[4096];
|
||||
THROW_ON_SYS_ERROR(getcwd(newWorkDir, sizeof(newWorkDir)) == NULL, FormatError, "unable to get cwd");
|
||||
|
||||
// Error if the new working directory is not equal to the original current working directory. This means that
|
||||
// PostgreSQL and pgBackrest have a different idea about where the PostgreSQL data directory is located.
|
||||
if (strcmp(currentWorkDir, newWorkDir) != 0)
|
||||
THROW_FMT(AssertError, "working path '%s' is not the same path as '%s'", currentWorkDir, strPtr(pgPath));
|
||||
}
|
||||
|
||||
result = strNewFmt("%s/%s", strPtr(pgPath), strPtr(walFile));
|
||||
}
|
||||
else
|
||||
result = strDup(walFile);
|
||||
|
@ -64,7 +64,7 @@ void archiveAsyncStatusErrorWrite(ArchiveMode archiveMode, const String *walSegm
|
||||
|
||||
bool walIsPartial(const String *walSegment);
|
||||
bool walIsSegment(const String *walSegment);
|
||||
String *walPath(const String *walFile);
|
||||
String *walPath(const String *walFile, const String *pgPath, const String *command);
|
||||
String *walSegmentFind(const Storage *storage, const String *archiveId, const String *walSegment, TimeMSec timeout);
|
||||
String *walSegmentNext(const String *walSegment, size_t walSegmentSize, unsigned int pgVersion);
|
||||
StringList *walSegmentRange(const String *walSegmentBegin, size_t walSegmentSize, unsigned int pgVersion, unsigned int range);
|
||||
|
@ -132,7 +132,8 @@ cmdArchiveGet(void)
|
||||
String *walSegment = strBase(strLstGet(commandParam, 0));
|
||||
|
||||
// Destination is wherever we were told to move the WAL segment
|
||||
const String *walDestination = walPath(strLstGet(commandParam, 1));
|
||||
const String *walDestination =
|
||||
walPath(strLstGet(commandParam, 1), cfgOptionStr(cfgOptPgPath), STR(cfgCommandName(cfgCommand())));
|
||||
|
||||
// Async get can only be performed on WAL segments, history or other files must use synchronous mode
|
||||
if (cfgOptionBool(cfgOptArchiveAsync) && walIsSegment(walSegment))
|
||||
|
@ -268,7 +268,7 @@ cmdArchivePush(void)
|
||||
lockStopTest();
|
||||
|
||||
// Get the segment name
|
||||
String *walFile = walPath(strLstGet(commandParam, 0));
|
||||
String *walFile = walPath(strLstGet(commandParam, 0), cfgOptionStr(cfgOptPgPath), STR(cfgCommandName(cfgCommand())));
|
||||
String *archiveFile = strBase(walFile);
|
||||
|
||||
if (cfgOptionBool(cfgOptArchiveAsync))
|
||||
|
@ -172,14 +172,39 @@ testRun(void)
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("walPath()"))
|
||||
{
|
||||
THROW_ON_SYS_ERROR(chdir("/tmp") != 0, PathMissingError, "unable to chdir()");
|
||||
const String *pgPath = storagePathP(storageTest, STRDEF("pg"));
|
||||
storagePathCreateP(storageTest, pgPath);
|
||||
|
||||
TEST_RESULT_STR(
|
||||
strPtr(walPath(strNew("/absolute/path"), pgPath, strNew("test"))), "/absolute/path", "absolute path");
|
||||
|
||||
THROW_ON_SYS_ERROR(chdir(strPtr(pgPath)) != 0, PathMissingError, "unable to chdir()");
|
||||
TEST_RESULT_STR_STR(
|
||||
walPath(strNew("relative/path"), pgPath, strNew("test")), strNewFmt("%s/relative/path", strPtr(pgPath)),
|
||||
"relative path");
|
||||
|
||||
|
||||
const String *pgPathLink = storagePathP(storageTest, STRDEF("pg-link"));
|
||||
THROW_ON_SYS_ERROR_FMT(
|
||||
symlink(strPtr(pgPath), strPtr(pgPathLink)) == -1, FileOpenError,
|
||||
"unable to create symlink '%s' to '%s'", strPtr(pgPath), strPtr(pgPathLink));
|
||||
|
||||
THROW_ON_SYS_ERROR(chdir(strPtr(pgPath)) != 0, PathMissingError, "unable to chdir()");
|
||||
TEST_RESULT_STR_STR(
|
||||
walPath(strNew("relative/path"), pgPathLink, strNew("test")), strNewFmt("%s/relative/path", strPtr(pgPathLink)),
|
||||
"relative path");
|
||||
|
||||
TEST_RESULT_STR(strPtr(walPath(strNew("/absolute/path"))), "/absolute/path", "absolute path");
|
||||
TEST_RESULT_STR(strPtr(walPath(strNew("relative/path"))), "/tmp/relative/path", "relative path");
|
||||
|
||||
THROW_ON_SYS_ERROR(chdir("/") != 0, PathMissingError, "unable to chdir()");
|
||||
TEST_ERROR(
|
||||
walPath(strNew("relative/path"), pgPathLink, strNew("test")), AssertError,
|
||||
hrnReplaceKey("working path '/' is not the same path as '{[path]}/pg-link'"));
|
||||
|
||||
TEST_RESULT_STR(strPtr(walPath(strNew("relative/path"))), "/relative/path", "relative path");
|
||||
TEST_ERROR(
|
||||
walPath(strNew("relative/path"), NULL, strNew("test")), OptionRequiredError,
|
||||
"option 'pg1-path' must be specified when relative wal paths are used\n"
|
||||
"HINT: is %f passed to test instead of %p?\n"
|
||||
"HINT: PostgreSQL may pass relative paths even with %p depending on the environment.");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
|
@ -588,6 +588,8 @@ testRun(void)
|
||||
strLstAdd(argList, strNewFmt("--pg1-path=%s/db", testPath()));
|
||||
harnessCfgLoadRaw(strLstSize(argList), strLstPtr(argList));
|
||||
|
||||
THROW_ON_SYS_ERROR(chdir(strPtr(cfgOptionStr(cfgOptPgPath))) != 0, PathMissingError, "unable to chdir()");
|
||||
|
||||
HARNESS_FORK_BEGIN()
|
||||
{
|
||||
HARNESS_FORK_CHILD_BEGIN(0, false)
|
||||
@ -623,8 +625,6 @@ testRun(void)
|
||||
|
||||
// Write out a WAL segment for success
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
THROW_ON_SYS_ERROR(chdir(strPtr(cfgOptionStr(cfgOptPgPath))) != 0, PathMissingError, "unable to chdir()");
|
||||
|
||||
storagePutP(
|
||||
storageNewWriteP(storageSpoolWrite(), strNewFmt(STORAGE_SPOOL_ARCHIVE_IN "/%s", strPtr(walSegment))),
|
||||
BUFSTRDEF("SHOULD-BE-A-REAL-WAL-FILE"));
|
||||
|
@ -181,12 +181,23 @@ testRun(void)
|
||||
|
||||
TEST_ERROR(cmdArchivePush(), ParamRequiredError, "WAL segment to push required");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
StringList *argListTemp = strLstDup(argList);
|
||||
strLstAddZ(argListTemp, "pg_wal/000000010000000100000001");
|
||||
harnessCfgLoad(cfgCmdArchivePush, argListTemp);
|
||||
|
||||
TEST_ERROR(
|
||||
cmdArchivePush(), OptionRequiredError,
|
||||
"option 'pg1-path' must be specified when relative wal paths are used"
|
||||
"\nHINT: is %f passed to archive-push instead of %p?"
|
||||
"\nHINT: PostgreSQL may pass relative paths even with %p depending on the environment.");
|
||||
|
||||
// Create pg_control and archive.info
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
strLstAdd(argList, strNewFmt("--pg1-path=%s/pg", testPath()));
|
||||
strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath()));
|
||||
|
||||
StringList *argListTemp = strLstDup(argList);
|
||||
argListTemp = strLstDup(argList);
|
||||
strLstAddZ(argListTemp, "pg_wal/000000010000000100000001");
|
||||
harnessCfgLoad(cfgCmdArchivePush, argListTemp);
|
||||
|
||||
@ -415,7 +426,8 @@ testRun(void)
|
||||
strLstAddZ(argList, "pg_wal/bogus");
|
||||
harnessCfgLoadRaw(strLstSize(argList), strLstPtr(argList));
|
||||
|
||||
THROW_ON_SYS_ERROR(chdir(testPath()) != 0, PathMissingError, "unable to chdir()");
|
||||
storagePathCreateP(storageTest, cfgOptionStr(cfgOptPgPath));
|
||||
THROW_ON_SYS_ERROR(chdir(strPtr(cfgOptionStr(cfgOptPgPath))) != 0, PathMissingError, "unable to chdir()");
|
||||
|
||||
TEST_ERROR(
|
||||
cmdArchivePush(), ArchiveTimeoutError,
|
||||
|
Loading…
x
Reference in New Issue
Block a user