1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-07-05 00:28:52 +02:00

Remove cfgOptionId() and replace it with cfgParseOption().

cfgOptionId() did not recognize deprecated options which made the help command throw errors when they were specified on the command line. cfgParseOption() will correctly identify deprecated options.

cfgParseOption() can also be used in cfgParse() to reduce code duplication when parsing info out of the option value returned by optionFind().

Finally, code the option key index separately in parse.auto.c. For now they are simply added back together but future code will need them separated.
This commit is contained in:
David Steele
2020-10-20 11:24:26 -04:00
parent 6414ae9707
commit 41789d70d1
11 changed files with 578 additions and 547 deletions

View File

@ -143,7 +143,7 @@ sub buildConfigParse
} }
my $strOptionVal = my $strOptionVal =
($iOptionIdx > 1 ? "(" : '') . $strOptionEnum . ($iOptionIdx > 1 ? " + " . ($iOptionIdx - 1) . ')' : ''); ($rhOption->{&CFGDEF_GROUP} ? "(" . ($iOptionIdx - 1) . " << PARSE_KEY_IDX_SHIFT) | " : '') . $strOptionEnum;
# Add option # Add option
$strBuildSource .= $strBuildSource .=

View File

@ -12,6 +12,7 @@ Help Command
#include "common/memContext.h" #include "common/memContext.h"
#include "config/config.h" #include "config/config.h"
#include "config/define.h" #include "config/define.h"
#include "config/parse.h"
#include "version.h" #include "version.h"
/*********************************************************************************************************************************** /***********************************************************************************************************************************
@ -303,19 +304,21 @@ helpRender(void)
THROW(ParamInvalidError, "only one option allowed for option help"); THROW(ParamInvalidError, "only one option allowed for option help");
// Ensure the option is valid // Ensure the option is valid
const char *optionName = strZ(strLstGet(cfgCommandParam(), 0)); const String *optionName = strLstGet(cfgCommandParam(), 0);
ConfigOption optionId = cfgOptionId(optionName); CfgParseOptionResult option = cfgParseOption(optionName);
if (cfgOptionId(optionName) == -1) if (!option.found)
{ {
if (cfgDefOptionId(optionName) != -1) int optionId = cfgDefOptionId(strZ(optionName));
optionId = cfgOptionIdFromDefId(cfgDefOptionId(optionName), 0);
if (optionId == -1)
THROW_FMT(OptionInvalidError, "option '%s' is not valid for command '%s'", strZ(optionName), commandName);
else else
THROW_FMT(OptionInvalidError, "option '%s' is not valid for command '%s'", optionName, commandName); option.id = cfgOptionIdFromDefId((unsigned int)optionId, 0);
} }
// Output option summary and description // Output option summary and description
ConfigDefineOption optionDefId = cfgOptionDefIdFromId(optionId); ConfigDefineOption optionDefId = cfgOptionDefIdFromId(option.id);
strCatFmt( strCatFmt(
result, result,
@ -324,16 +327,16 @@ helpRender(void)
"%s\n" "%s\n"
"\n" "\n"
"%s\n", "%s\n",
optionName, cfgDefOptionName(optionDefId),
strZ(helpRenderText(STR(cfgDefOptionHelpSummary(commandId, optionDefId)), 0, true, CONSOLE_WIDTH)), strZ(helpRenderText(STR(cfgDefOptionHelpSummary(commandId, optionDefId)), 0, true, CONSOLE_WIDTH)),
strZ(helpRenderText(STR(cfgDefOptionHelpDescription(commandId, optionDefId)), 0, true, CONSOLE_WIDTH))); strZ(helpRenderText(STR(cfgDefOptionHelpDescription(commandId, optionDefId)), 0, true, CONSOLE_WIDTH)));
// Ouput current and default values if they exist // Ouput current and default values if they exist
const String *defaultValue = helpRenderValue(cfgOptionDefault(optionId)); const String *defaultValue = helpRenderValue(cfgOptionDefault(option.id));
const String *value = NULL; const String *value = NULL;
if (cfgOptionSource(optionId) != cfgSourceDefault) if (cfgOptionSource(option.id) != cfgSourceDefault)
value = helpRenderValue(cfgOption(optionId)); value = helpRenderValue(cfgOption(option.id));
if (value != NULL || defaultValue != NULL) if (value != NULL || defaultValue != NULL)
{ {

View File

@ -713,25 +713,6 @@ cfgOptionIndex(ConfigOption optionId)
FUNCTION_TEST_RETURN(configOptionData[optionId].index); FUNCTION_TEST_RETURN(configOptionData[optionId].index);
} }
/**********************************************************************************************************************************/
int
cfgOptionId(const char *optionName)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRINGZ, optionName);
FUNCTION_TEST_END();
ASSERT(optionName != NULL);
int result = -1;
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
if (strcmp(optionName, configOptionData[optionId].name) == 0)
result = optionId;
FUNCTION_TEST_RETURN(result);
}
/**********************************************************************************************************************************/ /**********************************************************************************************************************************/
ConfigOption ConfigOption
cfgOptionIdFromDefId(ConfigDefineOption optionDefId, unsigned int index) cfgOptionIdFromDefId(ConfigDefineOption optionDefId, unsigned int index)

View File

@ -193,9 +193,6 @@ ConfigDefineOption cfgOptionDefIdFromId(ConfigOption optionId);
// Parse a host option and extract the host and port (if it exists) // Parse a host option and extract the host and port (if it exists)
String *cfgOptionHostPort(ConfigOption optionId, unsigned int *port); String *cfgOptionHostPort(ConfigOption optionId, unsigned int *port);
// Get option id by name
int cfgOptionId(const char *optionName);
// Get the id for this option define // Get the id for this option define
ConfigOption cfgOptionIdFromDefId(ConfigDefineOption optionDefId, unsigned int index); ConfigOption cfgOptionIdFromDefId(ConfigDefineOption optionDefId, unsigned int index);

File diff suppressed because it is too large Load Diff

View File

@ -61,8 +61,12 @@ Parse option flags
// Indicate that option name has been deprecated and will be removed in a future release // Indicate that option name has been deprecated and will be removed in a future release
#define PARSE_DEPRECATE_FLAG (1 << 27) #define PARSE_DEPRECATE_FLAG (1 << 27)
// Mask to exclude all flags and get at the actual option id (only 12 bits allowed for option id, the rest reserved for flags) // Mask for option id (must be 0-255)
#define PARSE_OPTION_MASK 0xFFF #define PARSE_OPTION_MASK 0xFF
// Shift and mask for option key index (must be 0-255)
#define PARSE_KEY_IDX_SHIFT 8
#define PARSE_KEY_IDX_MASK 0xFF
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Include automatically generated data structure for getopt_long() Include automatically generated data structure for getopt_long()
@ -84,23 +88,46 @@ typedef struct ParseOption
#define FUNCTION_LOG_PARSE_OPTION_FORMAT(value, buffer, bufferSize) \ #define FUNCTION_LOG_PARSE_OPTION_FORMAT(value, buffer, bufferSize) \
typeToLog("ParseOption", buffer, bufferSize) typeToLog("ParseOption", buffer, bufferSize)
/*********************************************************************************************************************************** /**********************************************************************************************************************************/
Find an option by name in the option list // Helper to parse the option info into a structure
***********************************************************************************************************************************/ __attribute__((always_inline)) static inline CfgParseOptionResult
static unsigned int cfgParseOptionInfo(int info)
optionFind(const String *option)
{ {
unsigned int optionIdx = 0; return (CfgParseOptionResult)
while (optionList[optionIdx].name != NULL)
{ {
if (strcmp(strZ(option), optionList[optionIdx].name) == 0) .found = true,
.id = (info & PARSE_OPTION_MASK) + ((info >> PARSE_KEY_IDX_SHIFT) & PARSE_KEY_IDX_MASK),
.negate = info & PARSE_NEGATE_FLAG,
.reset = info & PARSE_RESET_FLAG,
.deprecated = info & PARSE_DEPRECATE_FLAG,
};
}
CfgParseOptionResult
cfgParseOption(const String *optionName)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, optionName);
FUNCTION_TEST_END();
ASSERT(optionName != NULL);
// Search for the option
unsigned int findIdx = 0;
while (optionList[findIdx].name != NULL)
{
if (strEqZ(optionName, optionList[findIdx].name))
break; break;
optionIdx++; findIdx++;
} }
return optionIdx; // If the option was found
if (optionList[findIdx].name != NULL)
FUNCTION_TEST_RETURN(cfgParseOptionInfo(optionList[findIdx].val));
FUNCTION_TEST_RETURN((CfgParseOptionResult){0});
} }
/*********************************************************************************************************************************** /***********************************************************************************************************************************
@ -432,7 +459,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
// Phase 1: parse command line parameters // Phase 1: parse command line parameters
// ------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------
int option; // Code returned by getopt_long int optionValue; // Value returned by getopt_long
int optionListIdx; // Index of option is list (if an option was returned) int optionListIdx; // Index of option is list (if an option was returned)
bool argFound = false; // Track args found to decide on error or help at the end bool argFound = false; // Track args found to decide on error or help at the end
StringList *commandParamList = NULL; // List of command parameters StringList *commandParamList = NULL; // List of command parameters
@ -449,9 +476,9 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
// Only the first non-option parameter should be treated as a command so track if the command has been set // Only the first non-option parameter should be treated as a command so track if the command has been set
bool commandSet = false; bool commandSet = false;
while ((option = getopt_long((int)argListSize, (char **)argList, "-:", optionList, &optionListIdx)) != -1) while ((optionValue = getopt_long((int)argListSize, (char **)argList, "-:", optionList, &optionListIdx)) != -1)
{ {
switch (option) switch (optionValue)
{ {
// Parse arguments that are not options, i.e. commands and parameters passed to commands // Parse arguments that are not options, i.e. commands and parameters passed to commands
case 1: case 1:
@ -517,71 +544,72 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
default: default:
{ {
// Get option id and flags from the option code // Get option id and flags from the option code
ConfigOption optionId = option & PARSE_OPTION_MASK; CfgParseOptionResult option = cfgParseOptionInfo(optionValue);
bool negate = option & PARSE_NEGATE_FLAG;
bool reset = option & PARSE_RESET_FLAG;
// Make sure the option id is valid // Make sure the option id is valid
ASSERT(optionId < CFG_OPTION_TOTAL); ASSERT(option.id < CFG_OPTION_TOTAL);
// Error if this option is secure and cannot be passed on the command line // Error if this option is secure and cannot be passed on the command line
if (cfgDefOptionSecure(cfgOptionDefIdFromId(optionId))) if (cfgDefOptionSecure(cfgOptionDefIdFromId(option.id)))
{ {
THROW_FMT( THROW_FMT(
OptionInvalidError, OptionInvalidError,
"option '%s' is not allowed on the command-line\n" "option '%s' is not allowed on the command-line\n"
"HINT: this option could expose secrets in the process list.\n" "HINT: this option could expose secrets in the process list.\n"
"HINT: specify the option in a configuration file or an environment variable instead.", "HINT: specify the option in a configuration file or an environment variable instead.",
cfgOptionName(optionId)); cfgOptionName(option.id));
} }
// If the the option has not been found yet then set it // If the the option has not been found yet then set it
if (!parseOptionList[optionId].found) if (!parseOptionList[option.id].found)
{ {
parseOptionList[optionId].found = true; parseOptionList[option.id].found = true;
parseOptionList[optionId].negate = negate; parseOptionList[option.id].negate = option.negate;
parseOptionList[optionId].reset = reset; parseOptionList[option.id].reset = option.reset;
parseOptionList[optionId].source = cfgSourceParam; parseOptionList[option.id].source = cfgSourceParam;
// Only set the argument if the option requires one // Only set the argument if the option requires one
if (optionList[optionListIdx].has_arg == required_argument) if (optionList[optionListIdx].has_arg == required_argument)
{ {
parseOptionList[optionId].valueList = strLstNew(); parseOptionList[option.id].valueList = strLstNew();
strLstAdd(parseOptionList[optionId].valueList, STR(optarg)); strLstAdd(parseOptionList[option.id].valueList, STR(optarg));
} }
} }
else else
{ {
// Make sure option is not negated more than once. It probably wouldn't hurt anything to accept this case // Make sure option is not negated more than once. It probably wouldn't hurt anything to accept this case
// but there's no point in allowing the user to be sloppy. // but there's no point in allowing the user to be sloppy.
if (parseOptionList[optionId].negate && negate) if (parseOptionList[option.id].negate && option.negate)
THROW_FMT(OptionInvalidError, "option '%s' is negated multiple times", cfgOptionName(optionId)); THROW_FMT(OptionInvalidError, "option '%s' is negated multiple times", cfgOptionName(option.id));
// Make sure option is not reset more than once. Same justification as negate. // Make sure option is not reset more than once. Same justification as negate.
if (parseOptionList[optionId].reset && reset) if (parseOptionList[option.id].reset && option.reset)
THROW_FMT(OptionInvalidError, "option '%s' is reset multiple times", cfgOptionName(optionId)); THROW_FMT(OptionInvalidError, "option '%s' is reset multiple times", cfgOptionName(option.id));
// Don't allow an option to be both negated and reset // Don't allow an option to be both negated and reset
if ((parseOptionList[optionId].reset && negate) || (parseOptionList[optionId].negate && reset)) if ((parseOptionList[option.id].reset && option.negate) ||
THROW_FMT(OptionInvalidError, "option '%s' cannot be negated and reset", cfgOptionName(optionId)); (parseOptionList[option.id].negate && option.reset))
{
THROW_FMT(OptionInvalidError, "option '%s' cannot be negated and reset", cfgOptionName(option.id));
}
// Don't allow an option to be both set and negated // Don't allow an option to be both set and negated
if (parseOptionList[optionId].negate != negate) if (parseOptionList[option.id].negate != option.negate)
THROW_FMT(OptionInvalidError, "option '%s' cannot be set and negated", cfgOptionName(optionId)); THROW_FMT(OptionInvalidError, "option '%s' cannot be set and negated", cfgOptionName(option.id));
// Don't allow an option to be both set and reset // Don't allow an option to be both set and reset
if (parseOptionList[optionId].reset != reset) if (parseOptionList[option.id].reset != option.reset)
THROW_FMT(OptionInvalidError, "option '%s' cannot be set and reset", cfgOptionName(optionId)); THROW_FMT(OptionInvalidError, "option '%s' cannot be set and reset", cfgOptionName(option.id));
// Add the argument // Add the argument
if (optionList[optionListIdx].has_arg == required_argument && if (optionList[optionListIdx].has_arg == required_argument &&
cfgDefOptionMulti(cfgOptionDefIdFromId(optionId))) cfgDefOptionMulti(cfgOptionDefIdFromId(option.id)))
{ {
strLstAdd(parseOptionList[optionId].valueList, strNew(optarg)); strLstAdd(parseOptionList[option.id].valueList, strNew(optarg));
} }
// Error if the option does not accept multiple arguments // Error if the option does not accept multiple arguments
else else
THROW_FMT(OptionInvalidError, "option '%s' cannot be set multiple times", cfgOptionName(optionId)); THROW_FMT(OptionInvalidError, "option '%s' cannot be set multiple times", cfgOptionName(option.id));
} }
break; break;
@ -647,29 +675,28 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
const String *value = STR(equalPtr + 1); const String *value = STR(equalPtr + 1);
// Find the option // Find the option
unsigned int optionIdx = optionFind(key); CfgParseOptionResult option = cfgParseOption(key);
// Warn if the option not found // Warn if the option not found
if (optionList[optionIdx].name == NULL) if (!option.found)
{ {
LOG_WARN_FMT("environment contains invalid option '%s'", strZ(key)); LOG_WARN_FMT("environment contains invalid option '%s'", strZ(key));
continue; continue;
} }
// Warn if negate option found in env // Warn if negate option found in env
else if (optionList[optionIdx].val & PARSE_NEGATE_FLAG) else if (option.negate)
{ {
LOG_WARN_FMT("environment contains invalid negate option '%s'", strZ(key)); LOG_WARN_FMT("environment contains invalid negate option '%s'", strZ(key));
continue; continue;
} }
// Warn if reset option found in env // Warn if reset option found in env
else if (optionList[optionIdx].val & PARSE_RESET_FLAG) else if (option.reset)
{ {
LOG_WARN_FMT("environment contains invalid reset option '%s'", strZ(key)); LOG_WARN_FMT("environment contains invalid reset option '%s'", strZ(key));
continue; continue;
} }
ConfigOption optionId = optionList[optionIdx].val & PARSE_OPTION_MASK; ConfigDefineOption optionDefId = cfgOptionDefIdFromId(option.id);
ConfigDefineOption optionDefId = cfgOptionDefIdFromId(optionId);
// Continue if the option is not valid for this command // Continue if the option is not valid for this command
if (!cfgDefOptionValid(commandId, optionDefId)) if (!cfgDefOptionValid(commandId, optionDefId))
@ -679,30 +706,30 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
THROW_FMT(OptionInvalidValueError, "environment variable '%s' must have a value", strZ(key)); THROW_FMT(OptionInvalidValueError, "environment variable '%s' must have a value", strZ(key));
// Continue if the option has already been specified on the command line // Continue if the option has already been specified on the command line
if (parseOptionList[optionId].found) if (parseOptionList[option.id].found)
continue; continue;
parseOptionList[optionId].found = true; parseOptionList[option.id].found = true;
parseOptionList[optionId].source = cfgSourceConfig; parseOptionList[option.id].source = cfgSourceConfig;
// Convert boolean to string // Convert boolean to string
if (cfgDefOptionType(optionDefId) == cfgDefOptTypeBoolean) if (cfgDefOptionType(optionDefId) == cfgDefOptTypeBoolean)
{ {
if (strEqZ(value, "n")) if (strEqZ(value, "n"))
parseOptionList[optionId].negate = true; parseOptionList[option.id].negate = true;
else if (!strEqZ(value, "y")) else if (!strEqZ(value, "y"))
THROW_FMT(OptionInvalidValueError, "environment boolean option '%s' must be 'y' or 'n'", strZ(key)); THROW_FMT(OptionInvalidValueError, "environment boolean option '%s' must be 'y' or 'n'", strZ(key));
} }
// Else split list/hash into separate values // Else split list/hash into separate values
else if (cfgDefOptionMulti(optionDefId)) else if (cfgDefOptionMulti(optionDefId))
{ {
parseOptionList[optionId].valueList = strLstNewSplitZ(value, ":"); parseOptionList[option.id].valueList = strLstNewSplitZ(value, ":");
} }
// Else add the string value // Else add the string value
else else
{ {
parseOptionList[optionId].valueList = strLstNew(); parseOptionList[option.id].valueList = strLstNew();
strLstAdd(parseOptionList[optionId].valueList, value); strLstAdd(parseOptionList[option.id].valueList, value);
} }
} }
} }
@ -750,31 +777,30 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
String *key = strLstGet(keyList, keyIdx); String *key = strLstGet(keyList, keyIdx);
// Find the optionName in the main list // Find the optionName in the main list
unsigned int optionIdx = optionFind(key); CfgParseOptionResult option = cfgParseOption(key);
// Warn if the option not found // Warn if the option not found
if (optionList[optionIdx].name == NULL) if (!option.found)
{ {
LOG_WARN_FMT("configuration file contains invalid option '%s'", strZ(key)); LOG_WARN_FMT("configuration file contains invalid option '%s'", strZ(key));
continue; continue;
} }
// Warn if negate option found in config // Warn if negate option found in config
else if (optionList[optionIdx].val & PARSE_NEGATE_FLAG) else if (option.negate)
{ {
LOG_WARN_FMT("configuration file contains negate option '%s'", strZ(key)); LOG_WARN_FMT("configuration file contains negate option '%s'", strZ(key));
continue; continue;
} }
// Warn if reset option found in config // Warn if reset option found in config
else if (optionList[optionIdx].val & PARSE_RESET_FLAG) else if (option.reset)
{ {
LOG_WARN_FMT("configuration file contains reset option '%s'", strZ(key)); LOG_WARN_FMT("configuration file contains reset option '%s'", strZ(key));
continue; continue;
} }
ConfigOption optionId = optionList[optionIdx].val & PARSE_OPTION_MASK; ConfigDefineOption optionDefId = cfgOptionDefIdFromId(option.id);
ConfigDefineOption optionDefId = cfgOptionDefIdFromId(optionId);
/// Warn if this option should be command-line only // Warn if this option should be command-line only
if (cfgDefOptionSection(optionDefId) == cfgDefSectionCommandLine) if (cfgDefOptionSection(optionDefId) == cfgDefSectionCommandLine)
{ {
LOG_WARN_FMT("configuration file contains command-line only option '%s'", strZ(key)); LOG_WARN_FMT("configuration file contains command-line only option '%s'", strZ(key));
@ -782,7 +808,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
} }
// Make sure this option does not appear in the same section with an alternate name // Make sure this option does not appear in the same section with an alternate name
const Variant *optionFoundKey = VARINT(optionId); const Variant *optionFoundKey = VARINT(option.id);
const Variant *optionFoundName = kvGet(optionFound, optionFoundKey); const Variant *optionFoundName = kvGet(optionFound, optionFoundKey);
if (optionFoundName != NULL) if (optionFoundName != NULL)
@ -820,20 +846,20 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
} }
// Continue if this option has already been found in another section or command-line/environment // Continue if this option has already been found in another section or command-line/environment
if (parseOptionList[optionId].found) if (parseOptionList[option.id].found)
continue; continue;
parseOptionList[optionId].found = true; parseOptionList[option.id].found = true;
parseOptionList[optionId].source = cfgSourceConfig; parseOptionList[option.id].source = cfgSourceConfig;
// Process list // Process list
if (iniSectionKeyIsList(config, section, key)) if (iniSectionKeyIsList(config, section, key))
{ {
// Error if the option cannot be specified multiple times // Error if the option cannot be specified multiple times
if (!cfgDefOptionMulti(optionDefId)) if (!cfgDefOptionMulti(optionDefId))
THROW_FMT(OptionInvalidError, "option '%s' cannot be set multiple times", cfgOptionName(optionId)); THROW_FMT(OptionInvalidError, "option '%s' cannot be set multiple times", cfgOptionName(option.id));
parseOptionList[optionId].valueList = iniGetList(config, section, key); parseOptionList[option.id].valueList = iniGetList(config, section, key);
} }
else else
{ {
@ -850,15 +876,15 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
if (cfgDefOptionType(optionDefId) == cfgDefOptTypeBoolean) if (cfgDefOptionType(optionDefId) == cfgDefOptTypeBoolean)
{ {
if (strEqZ(value, "n")) if (strEqZ(value, "n"))
parseOptionList[optionId].negate = true; parseOptionList[option.id].negate = true;
else if (!strEqZ(value, "y")) else if (!strEqZ(value, "y"))
THROW_FMT(OptionInvalidValueError, "boolean option '%s' must be 'y' or 'n'", strZ(key)); THROW_FMT(OptionInvalidValueError, "boolean option '%s' must be 'y' or 'n'", strZ(key));
} }
// Else add the string value // Else add the string value
else else
{ {
parseOptionList[optionId].valueList = strLstNew(); parseOptionList[option.id].valueList = strLstNew();
strLstAdd(parseOptionList[optionId].valueList, value); strLstAdd(parseOptionList[option.id].valueList, value);
} }
} }
} }

View File

@ -12,4 +12,16 @@ Functions
// Parse the command-line arguments and config file to produce final config data // Parse the command-line arguments and config file to produce final config data
void configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel); void configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel);
// Parse option name and return option info
typedef struct CfgParseOptionResult
{
bool found; // Was the option found?
ConfigOption id; // Option ID
bool negate; // Was the option negated?
bool reset; // Was the option reset?
bool deprecated; // Is the option deprecated?
} CfgParseOptionResult;
CfgParseOptionResult cfgParseOption(const String *optionName);
#endif #endif

View File

@ -8,6 +8,7 @@ Configuration Protocol Handler
#include "common/log.h" #include "common/log.h"
#include "common/memContext.h" #include "common/memContext.h"
#include "config/config.h" #include "config/config.h"
#include "config/parse.h"
#include "config/protocol.h" #include "config/protocol.h"
/*********************************************************************************************************************************** /***********************************************************************************************************************************
@ -37,7 +38,12 @@ configProtocol(const String *command, const VariantList *paramList, ProtocolServ
VariantList *optionList = varLstNew(); VariantList *optionList = varLstNew();
for (unsigned int optionIdx = 0; optionIdx < varLstSize(paramList); optionIdx++) for (unsigned int optionIdx = 0; optionIdx < varLstSize(paramList); optionIdx++)
varLstAdd(optionList, varDup(cfgOption(cfgOptionId(strZ(varStr(varLstGet(paramList, optionIdx))))))); {
CfgParseOptionResult option = cfgParseOption(varStr(varLstGet(paramList, optionIdx)));
CHECK(option.found);
varLstAdd(optionList, varDup(cfgOption(option.id)));
}
protocolServerResponse(server, varNewVarLst(optionList)); protocolServerResponse(server, varNewVarLst(optionList));
} }

View File

@ -309,7 +309,7 @@ testRun(void)
// ------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------
optionHelp = strZ(strNewFmt( optionHelp = strZ(strNewFmt(
"%s - 'archive-push' command - 'repo1-s3-host' option help\n" "%s - 'archive-push' command - 'repo-s3-host' option help\n"
"\n" "\n"
"S3 repository host.\n" "S3 repository host.\n"
"\n" "\n"
@ -379,6 +379,15 @@ testRun(void)
harnessCfgLoadRaw(strLstSize(argList), strLstPtr(argList)), "help for backup command, repo-hardlink option"); harnessCfgLoadRaw(strLstSize(argList), strLstPtr(argList)), "help for backup command, repo-hardlink option");
TEST_RESULT_STR_Z(helpRender(), optionHelp, " check text"); TEST_RESULT_STR_Z(helpRender(), optionHelp, " check text");
argList = strLstNew();
strLstAddZ(argList, "/path/to/pgbackrest");
strLstAddZ(argList, "help");
strLstAddZ(argList, "backup");
strLstAddZ(argList, "hardlink");
TEST_RESULT_VOID(
harnessCfgLoadRaw(strLstSize(argList), strLstPtr(argList)), "help for backup command, deprecated hardlink option");
TEST_RESULT_STR_Z(helpRender(), optionHelp, " check text");
// Check admonition // Check admonition
// ------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------
optionHelp = strZ(strNewFmt( optionHelp = strZ(strNewFmt(

View File

@ -24,9 +24,6 @@ testRun(void)
TEST_RESULT_INT(cfgOptionDefIdFromId(cfgOptPgHost + 6), cfgDefOptPgHost, "option id to def id"); TEST_RESULT_INT(cfgOptionDefIdFromId(cfgOptPgHost + 6), cfgDefOptPgHost, "option id to def id");
TEST_RESULT_INT(cfgOptionId("target"), cfgOptTarget, "option id from name");
TEST_RESULT_INT(cfgOptionId(BOGUS_STR), -1, "option id from invalid option name");
TEST_ERROR( TEST_ERROR(
cfgOptionIdFromDefId(999999, 6), AssertError, cfgOptionIdFromDefId(999999, 6), AssertError,
"assertion 'optionId != CFG_OPTION_TOTAL' failed"); "assertion 'optionId != CFG_OPTION_TOTAL' failed");

View File

@ -18,13 +18,15 @@ Test Configuration Parse
Option find test -- this is done a lot in the deprecated tests Option find test -- this is done a lot in the deprecated tests
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
static void static void
testOptionFind(const char *option, unsigned int value) testOptionFind(const char *optionName, unsigned int optionId, unsigned int optionKeyIdx, bool negate, bool reset, bool deprecated)
{ {
// If not testing for a missing option, then add the option offset that is already added to each option in the list CfgParseOptionResult option = cfgParseOption(STR(optionName));
if (value != 0)
value |= PARSE_OPTION_FLAG;
TEST_RESULT_INT(optionList[optionFind(strNew(option))].val, value, "check %s", option); TEST_RESULT_BOOL(option.found, true, "check %s found", optionName);
TEST_RESULT_UINT(option.id, optionId + optionKeyIdx, "check %s id %u", optionName, optionId + optionKeyIdx);
TEST_RESULT_BOOL(option.negate, negate, "check %s negate %d", optionName, negate);
TEST_RESULT_BOOL(option.reset, reset, "check %s reset %d", optionName, reset);
TEST_RESULT_BOOL(option.deprecated, deprecated, "check %s deprecated %d", optionName, deprecated);
} }
/*********************************************************************************************************************************** /***********************************************************************************************************************************
@ -1433,61 +1435,59 @@ testRun(void)
{ {
// Repository options // Repository options
// ------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------
testOptionFind("hardlink", PARSE_DEPRECATE_FLAG | cfgOptRepoHardlink); testOptionFind("hardlink", cfgOptRepoHardlink, 0, false, false, true);
testOptionFind("no-hardlink", PARSE_DEPRECATE_FLAG | PARSE_NEGATE_FLAG | cfgOptRepoHardlink); testOptionFind("no-hardlink", cfgOptRepoHardlink, 0, true, false, true);
testOptionFind("archive-queue-max", PARSE_DEPRECATE_FLAG | cfgOptArchivePushQueueMax); testOptionFind("archive-queue-max", cfgOptArchivePushQueueMax, 0, false, false, true);
testOptionFind("reset-archive-queue-max", PARSE_DEPRECATE_FLAG | PARSE_RESET_FLAG | cfgOptArchivePushQueueMax); testOptionFind("reset-archive-queue-max", cfgOptArchivePushQueueMax, 0, false, true, true);
testOptionFind("backup-cmd", PARSE_DEPRECATE_FLAG | cfgOptRepoHostCmd); testOptionFind("backup-cmd", cfgOptRepoHostCmd, 0, false, false, true);
testOptionFind("backup-config", PARSE_DEPRECATE_FLAG | cfgOptRepoHostConfig); testOptionFind("backup-config", cfgOptRepoHostConfig, 0, false, false, true);
testOptionFind("backup-host", PARSE_DEPRECATE_FLAG | cfgOptRepoHost); testOptionFind("backup-host", cfgOptRepoHost, 0, false, false, true);
testOptionFind("backup-ssh-port", PARSE_DEPRECATE_FLAG | cfgOptRepoHostPort); testOptionFind("backup-ssh-port", cfgOptRepoHostPort, 0, false, false, true);
testOptionFind("backup-user", PARSE_DEPRECATE_FLAG | cfgOptRepoHostUser); testOptionFind("backup-user", cfgOptRepoHostUser, 0, false, false, true);
testOptionFind("repo-cipher-pass", PARSE_DEPRECATE_FLAG | cfgOptRepoCipherPass); testOptionFind("repo-cipher-pass", cfgOptRepoCipherPass, 0, false, false, true);
testOptionFind("repo-cipher-type", PARSE_DEPRECATE_FLAG | cfgOptRepoCipherType); testOptionFind("repo-cipher-type", cfgOptRepoCipherType, 0, false, false, true);
testOptionFind("repo-path", PARSE_DEPRECATE_FLAG | cfgOptRepoPath); testOptionFind("repo-path", cfgOptRepoPath, 0, false, false, true);
testOptionFind("repo-type", PARSE_DEPRECATE_FLAG | cfgOptRepoType); testOptionFind("repo-type", cfgOptRepoType, 0, false, false, true);
testOptionFind("repo-s3-bucket", PARSE_DEPRECATE_FLAG | cfgOptRepoS3Bucket); testOptionFind("repo-s3-bucket", cfgOptRepoS3Bucket, 0, false, false, true);
testOptionFind("repo-s3-ca-file", PARSE_DEPRECATE_FLAG | cfgOptRepoS3CaFile); testOptionFind("repo-s3-ca-file", cfgOptRepoS3CaFile, 0, false, false, true);
testOptionFind("repo-s3-ca-path", PARSE_DEPRECATE_FLAG | cfgOptRepoS3CaPath); testOptionFind("repo-s3-ca-path", cfgOptRepoS3CaPath, 0, false, false, true);
testOptionFind("repo-s3-endpoint", PARSE_DEPRECATE_FLAG | cfgOptRepoS3Endpoint); testOptionFind("repo-s3-endpoint", cfgOptRepoS3Endpoint, 0, false, false, true);
testOptionFind("repo-s3-host", PARSE_DEPRECATE_FLAG | cfgOptRepoS3Host); testOptionFind("repo-s3-host", cfgOptRepoS3Host, 0, false, false, true);
testOptionFind("repo-s3-key", PARSE_DEPRECATE_FLAG | cfgOptRepoS3Key); testOptionFind("repo-s3-key", cfgOptRepoS3Key, 0, false, false, true);
testOptionFind("repo-s3-key-secret", PARSE_DEPRECATE_FLAG | cfgOptRepoS3KeySecret); testOptionFind("repo-s3-key-secret", cfgOptRepoS3KeySecret, 0, false, false, true);
testOptionFind("repo-s3-region", PARSE_DEPRECATE_FLAG | cfgOptRepoS3Region); testOptionFind("repo-s3-region", cfgOptRepoS3Region, 0, false, false, true);
testOptionFind("repo-s3-verify-ssl", PARSE_DEPRECATE_FLAG | cfgOptRepoS3VerifyTls); testOptionFind("repo-s3-verify-ssl", cfgOptRepoS3VerifyTls, 0, false, false, true);
testOptionFind("repo1-s3-verify-ssl", PARSE_DEPRECATE_FLAG | cfgOptRepoS3VerifyTls); testOptionFind("repo1-s3-verify-ssl", cfgOptRepoS3VerifyTls, 0, false, false, true);
testOptionFind("no-repo-s3-verify-ssl", PARSE_DEPRECATE_FLAG | PARSE_NEGATE_FLAG | cfgOptRepoS3VerifyTls); testOptionFind("no-repo-s3-verify-ssl", cfgOptRepoS3VerifyTls, 0, true, false, true);
// PostreSQL options // PostreSQL options
// ------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------
testOptionFind("db-cmd", PARSE_DEPRECATE_FLAG | cfgOptPgHostCmd); testOptionFind("db-cmd", cfgOptPgHostCmd, 0, false, false, true);
testOptionFind("db-config", PARSE_DEPRECATE_FLAG | cfgOptPgHostConfig); testOptionFind("db-config", cfgOptPgHostConfig, 0, false, false, true);
testOptionFind("db-host", PARSE_DEPRECATE_FLAG | cfgOptPgHost); testOptionFind("db-host", cfgOptPgHost, 0, false, false, true);
testOptionFind("db-path", PARSE_DEPRECATE_FLAG | cfgOptPgPath); testOptionFind("db-path", cfgOptPgPath, 0, false, false, true);
testOptionFind("db-port", PARSE_DEPRECATE_FLAG | cfgOptPgPort); testOptionFind("db-port", cfgOptPgPort, 0, false, false, true);
testOptionFind("db-socket-path", PARSE_DEPRECATE_FLAG | cfgOptPgSocketPath); testOptionFind("db-socket-path", cfgOptPgSocketPath, 0, false, false, true);
testOptionFind("db-ssh-port", PARSE_DEPRECATE_FLAG | cfgOptPgHostPort); testOptionFind("db-ssh-port", cfgOptPgHostPort, 0, false, false, true);
testOptionFind("db-user", PARSE_DEPRECATE_FLAG | cfgOptPgHostUser); testOptionFind("db-user", cfgOptPgHostUser, 0, false, false, true);
testOptionFind("no-db-user", 0); TEST_RESULT_BOOL(cfgParseOption(STR("no-db-user")).found, false, "no-db-user not found");
for (unsigned int optionIdx = 0; optionIdx < cfgDefOptionIndexTotal(cfgDefOptPgPath); optionIdx++) // Only check 1-8 since 8 was the max index when these option names were deprecated
for (unsigned int optionIdx = 0; optionIdx < 8; optionIdx++)
{ {
testOptionFind(strZ(strNewFmt("db%u-cmd", optionIdx + 1)), PARSE_DEPRECATE_FLAG | (cfgOptPgHostCmd + optionIdx)); testOptionFind(strZ(strNewFmt("db%u-cmd", optionIdx + 1)), cfgOptPgHostCmd, optionIdx, false, false, true);
testOptionFind( testOptionFind(strZ(strNewFmt("db%u-config", optionIdx + 1)), cfgOptPgHostConfig, optionIdx, false, false, true);
strZ(strNewFmt("db%u-config", optionIdx + 1)), PARSE_DEPRECATE_FLAG | (cfgOptPgHostConfig + optionIdx)); testOptionFind(strZ(strNewFmt("db%u-host", optionIdx + 1)), cfgOptPgHost, optionIdx, false, false, true);
testOptionFind(strZ(strNewFmt("db%u-host", optionIdx + 1)), PARSE_DEPRECATE_FLAG | (cfgOptPgHost + optionIdx)); testOptionFind(strZ(strNewFmt("db%u-path", optionIdx + 1)), cfgOptPgPath, optionIdx, false, false, true);
testOptionFind(strZ(strNewFmt("db%u-path", optionIdx + 1)), PARSE_DEPRECATE_FLAG | (cfgOptPgPath + optionIdx)); testOptionFind(strZ(strNewFmt("db%u-port", optionIdx + 1)), cfgOptPgPort, optionIdx, false, false, true);
testOptionFind(strZ(strNewFmt("db%u-port", optionIdx + 1)), PARSE_DEPRECATE_FLAG | (cfgOptPgPort + optionIdx)); testOptionFind(strZ(strNewFmt("db%u-socket-path", optionIdx + 1)), cfgOptPgSocketPath, optionIdx, false, false, true);
testOptionFind( testOptionFind(strZ(strNewFmt("db%u-ssh-port", optionIdx + 1)), cfgOptPgHostPort, optionIdx, false, false, true);
strZ(strNewFmt("db%u-socket-path", optionIdx + 1)), PARSE_DEPRECATE_FLAG | (cfgOptPgSocketPath + optionIdx)); testOptionFind(strZ(strNewFmt("db%u-user", optionIdx + 1)), cfgOptPgHostUser, optionIdx, false, false, true);
testOptionFind(
strZ(strNewFmt("db%u-ssh-port", optionIdx + 1)), PARSE_DEPRECATE_FLAG | (cfgOptPgHostPort + optionIdx));
testOptionFind(strZ(strNewFmt("db%u-user", optionIdx + 1)), PARSE_DEPRECATE_FLAG | (cfgOptPgHostUser + optionIdx));
} }
} }