1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-01-18 04:58:51 +02:00

Add verify output and verbose options.

These options allow the user to control how the verify results will be output to the console and log.
This commit is contained in:
Reid Thompson 2022-05-06 11:11:36 -04:00 committed by GitHub
parent f405fc6ae2
commit 65d22e4325
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 907 additions and 203 deletions

View File

@ -72,6 +72,21 @@
<p>Backup file bundling for improved small file support.</p>
</release-item>
<release-item>
<commit subject="Add verify output and verbose options.">
<github-pull-request id="1607"/>
</commit>
<release-item-contributor-list>
<release-item-contributor id="cynthia.shang"/>
<release-item-contributor id="reid.thompson"/>
<release-item-reviewer id="david.steele"/>
<release-item-reviewer id="stefan.fercot"/>
</release-item-contributor-list>
<p>Verify command to validate the contents of a repository.</p>
</release-item>
<release-item>
<commit subject="Remove dependency on pg_database.datlastsysoid.">
<github-pull-request id="1735"/>

View File

@ -151,7 +151,6 @@ command:
command-role:
local: {}
remote: {}
internal: true
version:
log-file: false
@ -306,6 +305,11 @@ option:
command:
info: {}
repo-ls: {}
verify:
default: none
allow-list:
- none
- text
allow-list:
- text
- json
@ -453,6 +457,14 @@ option:
command-role:
main: {}
verbose:
type: boolean
default: false
command:
verify: {}
command-role:
main: {}
# Command-line only local/remote options
#---------------------------------------------------------------------------------------------------------------------------------
exec-id:

View File

@ -2411,10 +2411,10 @@
<!-- OPERATION - VERIFY COMMAND -->
<command id="verify" name="Verify">
<summary>Verify the contents of the repository.</summary>
<summary>Verify contents of the repository.</summary>
<text>
<p>Verify will attempt to determine if the backups and archives in the repository are valid.</p>
<p>Verify determines if the backups and archives in the repository are valid.</p>
</text>
<option-list>
@ -2428,6 +2428,27 @@
<example>20150131-153358F_20150131-153401I</example>
</option>
<!-- ======================================================================================================= -->
<option id="output" name="Output">
<summary>Output type.</summary>
<text> <p>Output may be none (default) or text. Requesting text generates ouput to stdout.</p>
</text>
<example>text</example>
</option>
<!-- ======================================================================================================= -->
<option id="verbose" name="Verbose">
<summary>Verbose output.</summary>
<text>
<p>Verbose defaults to false, providing a minimal response with important information about errors in the repository. Specifying true provides more information about what was successfully verified.</p>
</text>
<example>y</example>
</option>
</option-list>
</command>

View File

@ -1,7 +1,7 @@
/***********************************************************************************************************************************
Verify Command
Verify the contents of the repository.
Verify contents of the repository.
***********************************************************************************************************************************/
#include "build.auto.h"
@ -13,6 +13,7 @@ Verify the contents of the repository.
#include "command/check/common.h"
#include "command/verify/file.h"
#include "command/verify/protocol.h"
#include "command/verify/verify.h"
#include "common/compress/helper.h"
#include "common/crypto/cipherBlock.h"
#include "common/debug.h"
@ -29,6 +30,12 @@ Verify the contents of the repository.
#include "protocol/parallel.h"
#include "storage/helper.h"
/***********************************************************************************************************************************
Constants
***********************************************************************************************************************************/
#define VERIFY_STATUS_OK "ok"
#define VERIFY_STATUS_ERROR "error"
/***********************************************************************************************************************************
Data Types and Structures
***********************************************************************************************************************************/
@ -233,7 +240,7 @@ verifyInfoFile(const String *pathFileName, bool keepFile, const String *cipherPa
if (result.errorCode == errorTypeCode(&ChecksumError))
strCat(errorMsg, strNewFmt(" %s", strZ(pathFileName)));
LOG_WARN(strZ(errorMsg));
LOG_DETAIL(strZ(errorMsg));
}
TRY_END();
}
@ -273,7 +280,7 @@ verifyArchiveInfoFile(void)
// If the info and info.copy checksums don't match each other than one (or both) of the files could be corrupt so
// log a warning but must trust main
if (!strEq(verifyArchiveInfo.checksum, verifyArchiveInfoCopy.checksum))
LOG_WARN("archive.info.copy does not match archive.info");
LOG_DETAIL("archive.info.copy does not match archive.info");
}
}
else
@ -326,7 +333,7 @@ verifyBackupInfoFile(void)
// If the info and info.copy checksums don't match each other than one (or both) of the files could be corrupt so
// log a warning but must trust main
if (!strEq(verifyBackupInfo.checksum, verifyBackupInfoCopy.checksum))
LOG_WARN("backup.info.copy does not match backup.info");
LOG_DETAIL("backup.info.copy does not match backup.info");
}
}
else
@ -393,7 +400,7 @@ verifyManifestFile(
// If the manifest and manifest.copy checksums don't match each other than one (or both) of the files could be
// corrupt so log a warning but trust main
if (!strEq(verifyManifestInfo.checksum, verifyManifestInfoCopy.checksum))
LOG_WARN_FMT("backup '%s' manifest.copy does not match manifest", strZ(backupResult->backupLabel));
LOG_DETAIL_FMT("backup '%s' manifest.copy does not match manifest", strZ(backupResult->backupLabel));
}
}
else
@ -411,7 +418,7 @@ verifyManifestFile(
// If loaded successfully, then return the copy as usable
if (verifyManifestInfoCopy.errorCode == 0)
{
LOG_WARN_FMT("%s/backup.manifest is missing or unusable, using copy", strZ(backupResult->backupLabel));
LOG_DETAIL_FMT("%s/backup.manifest is missing or unusable, using copy", strZ(backupResult->backupLabel));
result = verifyManifestInfoCopy.manifest;
}
@ -420,7 +427,7 @@ verifyManifestFile(
{
backupResult->status = backupMissingManifest;
LOG_WARN_FMT("manifest missing for '%s' - backup may have expired", strZ(backupResult->backupLabel));
LOG_DETAIL_FMT("manifest missing for '%s' - backup may have expired", strZ(backupResult->backupLabel));
}
}
else
@ -453,8 +460,7 @@ verifyManifestFile(
// If the PG data is not found in the backup.info history, then error and reset the result
if (!found)
{
LOG_ERROR_FMT(
errorTypeCode(&FileInvalidError),
LOG_INFO_FMT(
"'%s' may not be recoverable - PG data (id %u, version %s, system-id %" PRIu64 ") is not in the backup.info"
" history, skipping",
strZ(backupResult->backupLabel), manData->pgId, strZ(pgVersionToStr(manData->pgVersion)), manData->pgSystemId);
@ -562,9 +568,7 @@ verifyCreateArchiveIdRange(VerifyArchiveResult *archiveIdResult, StringList *wal
// PostgreSQL will ignore it
if (archiveIdResult->pgWalInfo.version <= PG_VERSION_92 && strEndsWithZ(walSegment, "FF"))
{
LOG_ERROR_FMT(
errorTypeCode(&FileInvalidError), "invalid WAL '%s' for '%s' exists, skipping", strZ(walSegment),
strZ(archiveIdResult->archiveId));
LOG_INFO_FMT("invalid WAL '%s' for '%s' exists, skipping", strZ(walSegment), strZ(archiveIdResult->archiveId));
(*jobErrorTotal)++;
@ -578,9 +582,7 @@ verifyCreateArchiveIdRange(VerifyArchiveResult *archiveIdResult, StringList *wal
{
if (strEq(walSegment, strSubN(strLstGet(walFileList, walFileIdx + 1), 0, WAL_SEGMENT_NAME_SIZE)))
{
LOG_ERROR_FMT(
errorTypeCode(&FileInvalidError), "duplicate WAL '%s' for '%s' exists, skipping", strZ(walSegment),
strZ(archiveIdResult->archiveId));
LOG_INFO_FMT("duplicate WAL '%s' for '%s' exists, skipping", strZ(walSegment), strZ(archiveIdResult->archiveId));
(*jobErrorTotal)++;
@ -783,7 +785,7 @@ verifyArchive(VerifyJobData *const jobData)
else
{
// No valid WAL to process (may be only duplicates or nothing in WAL path) - remove WAL path from the list
LOG_WARN_FMT(
LOG_DETAIL_FMT(
"path '%s/%s' does not contain any valid WAL to be processed", strZ(archiveResult->archiveId),
strZ(walPath));
strLstRemoveIdx(jobData->walPathList, 0);
@ -806,7 +808,7 @@ verifyArchive(VerifyJobData *const jobData)
else
{
// Log that no WAL paths exist in the archive Id dir - remove the archive Id from the list (nothing to process)
LOG_WARN_FMT("archive path '%s' is empty", strZ(strLstGet(jobData->archiveIdList, 0)));
LOG_DETAIL_FMT("archive path '%s' is empty", strZ(strLstGet(jobData->archiveIdList, 0)));
strLstRemoveIdx(jobData->archiveIdList, 0);
}
}
@ -836,7 +838,8 @@ verifyBackup(VerifyJobData *const jobData)
// If result list is empty or the last processed is not equal to the backup being processed, then initialize the backup
// data and results
if (lstEmpty(jobData->backupResultList) ||
!strEq(((VerifyBackupResult *)lstGetLast(jobData->backupResultList))->backupLabel, strLstGet(jobData->backupList, 0)))
!strEq(
((VerifyBackupResult *)lstGetLast(jobData->backupResultList))->backupLabel, strLstGet(jobData->backupList, 0)))
{
MEM_CONTEXT_BEGIN(lstMemContext(jobData->backupResultList))
{
@ -1045,9 +1048,7 @@ verifyBackup(VerifyJobData *const jobData)
{
// Nothing to process so report an error, free the manifest, set the status, and remove the backup from processing
// list
LOG_ERROR_FMT(
errorTypeCode(&FileInvalidError), "backup '%s' manifest does not contain any target files to verify",
strZ(backupResult->backupLabel));
LOG_INFO_FMT("backup '%s' manifest does not contain any target files to verify", strZ(backupResult->backupLabel));
jobData->jobErrorTotal++;
@ -1157,8 +1158,7 @@ verifyLogInvalidResult(const String *fileType, VerifyResult verifyResult, unsign
FUNCTION_TEST_RETURN(UINT, 0);
}
LOG_ERROR_PID_FMT(
processId, errorTypeCode(&FileInvalidError), "%s '%s'", verifyErrorMsg(verifyResult), strZ(filePathName));
LOG_INFO_PID_FMT(processId, "%s '%s'", verifyErrorMsg(verifyResult), strZ(filePathName));
FUNCTION_TEST_RETURN(UINT, 1);
}
@ -1224,9 +1224,7 @@ verifySetBackupCheckArchive(
if (!strEmpty(missingFromHistory))
{
LOG_ERROR_FMT(
errorTypeCode(&ArchiveMismatchError), "archiveIds '%s' are not in the archive.info history list",
strZ(missingFromHistory));
LOG_INFO_FMT("archiveIds '%s' are not in the archive.info history list", strZ(missingFromHistory));
(*jobErrorTotal)++;
}
@ -1275,33 +1273,74 @@ verifyAddInvalidWalFile(List *walRangeList, VerifyResult fileResult, const Strin
FUNCTION_TEST_RETURN_VOID();
}
/***********************************************************************************************************************************
Create file errors string
***********************************************************************************************************************************/
static String *
verifyCreateFileErrorsStr(
const unsigned int errMissing, const unsigned int errChecksum, const unsigned int errSize, const unsigned int errOther,
const bool verboseText)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(UINT, errMissing); // Number of files missing
FUNCTION_TEST_PARAM(UINT, errChecksum); // Number of files with checksum errors
FUNCTION_TEST_PARAM(UINT, errSize); // Number of files with invalid size
FUNCTION_TEST_PARAM(UINT, errOther); // Number of files with other errors
FUNCTION_TEST_PARAM(BOOL, verboseText); // Is verbose output requested
FUNCTION_TEST_END();
String *result = strNew();
MEM_CONTEXT_TEMP_BEGIN()
{
// List all if verbose text, otherwise only list if type has errors
strCatFmt(
result, "\n %s%s%s%s",
verboseText || errMissing ? strZ(strNewFmt("missing: %u, ", errMissing)) : "",
verboseText || errChecksum ? strZ(strNewFmt("checksum invalid: %u, ", errChecksum)) : "",
verboseText || errSize ? strZ(strNewFmt("size invalid: %u, ", errSize)) : "",
verboseText || errOther ? strZ(strNewFmt("other: %u", errOther)) : "");
// Clean up trailing comma when necessary
if (strEndsWithZ(result, ", "))
strTrunc(result, (int)strSize(result) - 2);
}
MEM_CONTEXT_TEMP_END();
FUNCTION_TEST_RETURN(STRING, result);
}
/***********************************************************************************************************************************
Render the results of the verify command
***********************************************************************************************************************************/
static String *
verifyRender(List *archiveIdResultList, List *backupResultList)
verifyRender(const List *const archiveIdResultList, const List *const backupResultList, const bool verboseText)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(LIST, archiveIdResultList); // Result list for all archive Ids in the repo
FUNCTION_TEST_PARAM(LIST, backupResultList); // Result list for all backups in the repo
FUNCTION_TEST_PARAM(BOOL, verboseText); // Is verbose output requested?
FUNCTION_TEST_END();
ASSERT(archiveIdResultList != NULL);
ASSERT(backupResultList != NULL);
String *result = strCatZ(strNew(), "Results:");
String *result = strNew();
// Render archive results
if (lstEmpty(archiveIdResultList))
if (verboseText && lstEmpty(archiveIdResultList))
strCatZ(result, "\n archiveId: none found");
else
{
for (unsigned int archiveIdx = 0; archiveIdx < lstSize(archiveIdResultList); archiveIdx++)
{
VerifyArchiveResult *archiveIdResult = lstGet(archiveIdResultList, archiveIdx);
strCatFmt(
result, "\n archiveId: %s, total WAL checked: %u, total valid WAL: %u", strZ(archiveIdResult->archiveId),
archiveIdResult->totalWalFile, archiveIdResult->totalValidWal);
if (verboseText || archiveIdResult->totalWalFile - archiveIdResult->totalValidWal != 0)
{
strCatFmt(
result, "\n archiveId: %s, total WAL checked: %u, total valid WAL: %u", strZ(archiveIdResult->archiveId),
archiveIdResult->totalWalFile, archiveIdResult->totalValidWal);
}
if (archiveIdResult->totalWalFile > 0)
{
@ -1337,15 +1376,15 @@ verifyRender(List *archiveIdResultList, List *backupResultList)
}
}
strCatFmt(
result, "\n missing: %u, checksum invalid: %u, size invalid: %u, other: %u", errMissing, errChecksum,
errSize, errOther);
// Create/append file errors string
if (verboseText || errMissing + errChecksum + errSize + errOther > 0)
strCat(result, verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText));
}
}
}
// Render backup results
if (lstEmpty(backupResultList))
if (verboseText && lstEmpty(backupResultList))
strCatZ(result, "\n backup: none found");
else
{
@ -1377,9 +1416,12 @@ verifyRender(List *archiveIdResultList, List *backupResultList)
}
}
strCatFmt(
result, "\n backup: %s, status: %s, total files checked: %u, total valid files: %u",
strZ(backupResult->backupLabel), status, backupResult->totalFileVerify, backupResult->totalFileValid);
if (verboseText || (strcmp(status, "valid") != 0 && strcmp(status, "in-progress") != 0))
{
strCatFmt(
result, "\n backup: %s, status: %s, total files checked: %u, total valid files: %u",
strZ(backupResult->backupLabel), status, backupResult->totalFileVerify, backupResult->totalFileValid);
}
if (backupResult->totalFileVerify > 0)
{
@ -1402,9 +1444,9 @@ verifyRender(List *archiveIdResultList, List *backupResultList)
errOther++;
}
strCatFmt(
result, "\n missing: %u, checksum invalid: %u, size invalid: %u, other: %u", errMissing, errChecksum,
errSize, errOther);
// Create/append file errors string
if (verboseText || errMissing + errChecksum + errSize + errOther > 0)
strCat(result, verifyCreateFileErrorsStr(errMissing, errChecksum, errSize, errOther, verboseText));
}
}
}
@ -1416,16 +1458,17 @@ verifyRender(List *archiveIdResultList, List *backupResultList)
Process the verify command
***********************************************************************************************************************************/
static String *
verifyProcess(unsigned int *errorTotal)
verifyProcess(const bool verboseText)
{
FUNCTION_LOG_BEGIN(logLevelDebug);
FUNCTION_TEST_PARAM_P(UINT, errorTotal); // Pointer to overall job error total
FUNCTION_TEST_PARAM(BOOL, verboseText); // Is verbose output requested?
FUNCTION_LOG_END();
String *result = NULL;
String *const result = strNew();
MEM_CONTEXT_TEMP_BEGIN()
{
unsigned int errorTotal = 0;
String *resultStr = strNew();
// Get the repo storage in case it is remote and encryption settings need to be pulled down
@ -1437,8 +1480,8 @@ verifyProcess(unsigned int *errorTotal)
// If a usable backup.info file is not found, then report an error in the log
if (backupInfo == NULL)
{
LOG_ERROR(errorTypeCode(&FormatError), "No usable backup.info file");
(*errorTotal)++;
strCatZ(resultStr, "\n No usable backup.info file");
errorTotal++;
}
// Get a usable archive info file
@ -1447,8 +1490,8 @@ verifyProcess(unsigned int *errorTotal)
// If a usable archive.info file is not found, then report an error in the log
if (archiveInfo == NULL)
{
LOG_ERROR(errorTypeCode(&FormatError), "No usable archive.info file");
(*errorTotal)++;
strCatZ(resultStr, "\n No usable archive.info file");
errorTotal++;
}
// If both a usable archive info and backup info file were found, then proceed with verification
@ -1461,14 +1504,14 @@ verifyProcess(unsigned int *errorTotal)
}
CATCH_ANY()
{
LOG_ERROR(errorTypeCode(&FormatError), errorMessage());
(*errorTotal)++;
strCatFmt(resultStr, "\n%s", errorMessage());
errorTotal++;
}
TRY_END();
}
// If valid info files, then begin process of checking backups and archives in the repo
if ((*errorTotal) == 0)
if (errorTotal == 0)
{
// Initialize the job data
VerifyJobData jobData =
@ -1503,7 +1546,7 @@ verifyProcess(unsigned int *errorTotal)
// Warn if there are no archives or there are no backups in the repo so that the callback need not try to
// distinguish between having processed all of the list or if the list was missing in the first place
if (strLstEmpty(jobData.archiveIdList) || strLstEmpty(jobData.backupList))
LOG_WARN_FMT("no %s exist in the repo", strLstEmpty(jobData.archiveIdList) ? "archives" : "backups");
LOG_DETAIL_FMT("no %s exist in the repo", strLstEmpty(jobData.archiveIdList) ? "archives" : "backups");
// If there are no archives to process, then set the processing flag to skip to processing the backups
if (strLstEmpty(jobData.archiveIdList))
@ -1603,8 +1646,8 @@ verifyProcess(unsigned int *errorTotal)
else
{
// Log a protocol error and increment the jobErrorTotal
LOG_ERROR_PID_FMT(
processId, errorTypeCode(&ProtocolError),
LOG_INFO_PID_FMT(
processId,
"%s %s: [%d] %s", verifyErrorMsg(verifyOtherError), strZ(filePathName),
protocolParallelJobErrorCode(job), strZ(protocolParallelJobErrorMessage(job)));
@ -1646,19 +1689,21 @@ verifyProcess(unsigned int *errorTotal)
// ??? Need to do the final reconciliation - checking backup required WAL against, valid WAL
// Report results
resultStr = verifyRender(jobData.archiveIdResultList, jobData.backupResultList);
resultStr = verifyRender(jobData.archiveIdResultList, jobData.backupResultList, verboseText);
}
else
LOG_WARN("no archives or backups exist in the repo");
strCatZ(resultStr, "\n no archives or backups exist in the repo");
(*errorTotal) += jobData.jobErrorTotal;
errorTotal += jobData.jobErrorTotal;
}
MEM_CONTEXT_PRIOR_BEGIN()
// If verbose output or errors then output results
if (verboseText || errorTotal > 0)
{
result = strDup(resultStr);
strCatFmt(
result, "stanza: %s\nstatus: %s%s", strZ(cfgOptionStr(cfgOptStanza)),
errorTotal > 0 ? VERIFY_STATUS_ERROR : VERIFY_STATUS_OK, strZ(resultStr));
}
MEM_CONTEXT_PRIOR_END();
}
MEM_CONTEXT_TEMP_END();
@ -1673,16 +1718,21 @@ cmdVerify(void)
MEM_CONTEXT_TEMP_BEGIN()
{
unsigned int errorTotal = 0;
String *result = verifyProcess(&errorTotal);
const String *const result = verifyProcess(cfgOptionBool(cfgOptVerbose));
// Output results if any
if (strSize(result) > 0)
if (!strEmpty(result))
{
// Log results
LOG_INFO_FMT("%s", strZ(result));
// Throw an error if any encountered
if (errorTotal > 0)
THROW_FMT(RuntimeError, "%u fatal errors encountered, see log for details", errorTotal);
// Output to console when requested
if (cfgOptionStrId(cfgOptOutput) == CFGOPTVAL_OUTPUT_TEXT)
{
ioFdWriteOneStr(STDOUT_FILENO, result);
ioFdWriteOneStr(STDOUT_FILENO, LF_STR);
}
}
}
MEM_CONTEXT_TEMP_END();

View File

@ -126,8 +126,9 @@ Option constants
#define CFGOPT_TLS_SERVER_KEY_FILE "tls-server-key-file"
#define CFGOPT_TLS_SERVER_PORT "tls-server-port"
#define CFGOPT_TYPE "type"
#define CFGOPT_VERBOSE "verbose"
#define CFG_OPTION_TOTAL 154
#define CFG_OPTION_TOTAL 155
/***********************************************************************************************************************************
Option value constants
@ -195,6 +196,8 @@ Option value constants
#define CFGOPTVAL_OUTPUT_JSON STRID5("json", 0x73e6a0)
#define CFGOPTVAL_OUTPUT_JSON_Z "json"
#define CFGOPTVAL_OUTPUT_NONE STRID5("none", 0x2b9ee0)
#define CFGOPTVAL_OUTPUT_NONE_Z "none"
#define CFGOPTVAL_OUTPUT_TEXT STRID5("text", 0xa60b40)
#define CFGOPTVAL_OUTPUT_TEXT_Z "text"
@ -507,6 +510,7 @@ typedef enum
cfgOptTlsServerKeyFile,
cfgOptTlsServerPort,
cfgOptType,
cfgOptVerbose,
} ConfigOption;
#endif

View File

@ -3068,10 +3068,31 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =
(
PARSE_RULE_OPTION_COMMAND(cfgCmdInfo)
PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs)
PARSE_RULE_OPTION_COMMAND(cfgCmdVerify)
),
PARSE_RULE_OPTIONAL
(
PARSE_RULE_OPTIONAL_GROUP
(
PARSE_RULE_FILTER_CMD
(
PARSE_RULE_VAL_CMD(cfgCmdVerify),
),
PARSE_RULE_OPTIONAL_ALLOW_LIST
(
PARSE_RULE_VAL_STRID(parseRuleValStrIdNone),
PARSE_RULE_VAL_STRID(parseRuleValStrIdText),
),
PARSE_RULE_OPTIONAL_DEFAULT
(
PARSE_RULE_VAL_STRID(parseRuleValStrIdNone),
PARSE_RULE_VAL_STR(parseRuleValStrQT_none_QT),
),
),
PARSE_RULE_OPTIONAL_GROUP
(
PARSE_RULE_OPTIONAL_ALLOW_LIST
@ -8948,6 +8969,31 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =
),
),
),
// -----------------------------------------------------------------------------------------------------------------------------
PARSE_RULE_OPTION
(
PARSE_RULE_OPTION_NAME("verbose"),
PARSE_RULE_OPTION_TYPE(cfgOptTypeBoolean),
PARSE_RULE_OPTION_REQUIRED(true),
PARSE_RULE_OPTION_SECTION(cfgSectionCommandLine),
PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST
(
PARSE_RULE_OPTION_COMMAND(cfgCmdVerify)
),
PARSE_RULE_OPTIONAL
(
PARSE_RULE_OPTIONAL_GROUP
(
PARSE_RULE_OPTIONAL_DEFAULT
(
PARSE_RULE_VAL_BOOL_FALSE,
),
),
),
),
};
/***********************************************************************************************************************************
@ -9342,6 +9388,7 @@ static const uint8_t optionResolveOrder[] =
cfgOptTlsServerKeyFile,
cfgOptTlsServerPort,
cfgOptType,
cfgOptVerbose,
cfgOptArchiveCheck,
cfgOptArchiveCopy,
cfgOptArchiveModeCheck,

View File

@ -836,7 +836,7 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: verify
total: 8
total: 12
coverage:
- command/verify/file

View File

@ -69,6 +69,7 @@ testRun(void)
" stanza-upgrade Upgrade a stanza.\n"
" start Allow pgBackRest processes to run.\n"
" stop Stop pgBackRest processes from running.\n"
" verify Verify contents of the repository.\n"
" version Get version.\n"
"\n"
"Use 'pgbackrest help [command]' for more information.\n",

File diff suppressed because it is too large Load Diff