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

More config parsing in C in preparation for all config parsing in C.

This commit is contained in:
David Steele 2017-12-05 10:09:07 -05:00
parent 4f1725dc36
commit 8d4674031e
15 changed files with 531 additions and 252 deletions

View File

@ -83,14 +83,17 @@ sub buildConfigParse
"${strOptionPrefix}${iOptionIdx}-" . substr($strOption, length($strOptionPrefix) + 1) : $strOption;
# Generate option value used for parsing (offset is added so options don't conflict with getopt_long return values)
my $strOptionVal = 'PARSE_OPTION_OFFSET + ' . $strOptionEnum . ($iOptionIdx > 1 ? " + " . ($iOptionIdx - 1) : '');
my $strOptionFlag = 'PARSE_OPTION_FLAG |';
my $strOptionVal =
($iOptionIdx > 1 ? "(" : '') . $strOptionEnum . ($iOptionIdx > 1 ? " + " . ($iOptionIdx - 1) . ')' : '');
# Add option
$strBuildSource .=
" {\n" .
" .name = \"${strOptionName}\",\n" .
$strOptionArg .
" .val = ${strOptionVal},\n" .
" .val = ${strOptionFlag} ${strOptionVal},\n" .
" },\n";
# Add negation when defined
@ -99,7 +102,7 @@ sub buildConfigParse
$strBuildSource .=
" {\n" .
" .name = \"no-${strOptionName}\",\n" .
" .val = ${strOptionVal},\n" .
" .val = ${strOptionFlag} PARSE_NEGATE_FLAG | ${strOptionVal},\n" .
" },\n";
}
}

View File

@ -54,6 +54,10 @@
<release-item>
<p>Replace <code>cfgCommandTotal()</code>/<code>cfgOptionTotal()</code> functions with constants. The constants are applicable in more cases and allow the compiler to optimize certain loops more efficiently.</p>
</release-item>
<release-item>
<p>More config parsing in C in preparation for all config parsing in C.</p>
</release-item>
</release-development-list>
</release-core-list>

View File

@ -1,5 +1,5 @@
CC=gcc
CFLAGS=-I. -Wfatal-errors -Wall -Wextra -Wwrite-strings -Wno-clobbered -std=c99 -funroll-loops -ftree-vectorize
CFLAGS=-I. -Wfatal-errors -Wall -Wextra -Wwrite-strings -Wno-clobbered -std=c99 -O2 -funroll-loops -ftree-vectorize
DESTDIR=
pgbackrest: \

View File

@ -31,6 +31,7 @@ Define errors
ERROR_DEFINE(ERROR_CODE_MIN, AssertError, RuntimeError);
ERROR_DEFINE(ERROR_CODE_MIN + 04, FormatError, RuntimeError);
ERROR_DEFINE(ERROR_CODE_MIN + 05, CommandRequiredError, FormatError);
ERROR_DEFINE(ERROR_CODE_MIN + 23, CommandInvalidError, FormatError);
ERROR_DEFINE(ERROR_CODE_MIN + 31, OptionInvalidError, FormatError);
ERROR_DEFINE(ERROR_CODE_MIN + 69, MemoryError, RuntimeError);

View File

@ -17,6 +17,7 @@ typedef struct ErrorType ErrorType;
ERROR_DECLARE(AssertError);
ERROR_DECLARE(FormatError);
ERROR_DECLARE(CommandRequiredError);
ERROR_DECLARE(CommandInvalidError);
ERROR_DECLARE(OptionInvalidError);
ERROR_DECLARE(MemoryError);

View File

@ -11,778 +11,778 @@ static const struct option optionList[] =
{
{
.name = "archive-async",
.val = PARSE_OPTION_OFFSET + cfgOptArchiveAsync,
.val = PARSE_OPTION_FLAG | cfgOptArchiveAsync,
},
{
.name = "no-archive-async",
.val = PARSE_OPTION_OFFSET + cfgOptArchiveAsync,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptArchiveAsync,
},
{
.name = "archive-check",
.val = PARSE_OPTION_OFFSET + cfgOptArchiveCheck,
.val = PARSE_OPTION_FLAG | cfgOptArchiveCheck,
},
{
.name = "no-archive-check",
.val = PARSE_OPTION_OFFSET + cfgOptArchiveCheck,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptArchiveCheck,
},
{
.name = "archive-copy",
.val = PARSE_OPTION_OFFSET + cfgOptArchiveCopy,
.val = PARSE_OPTION_FLAG | cfgOptArchiveCopy,
},
{
.name = "no-archive-copy",
.val = PARSE_OPTION_OFFSET + cfgOptArchiveCopy,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptArchiveCopy,
},
{
.name = "archive-queue-max",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptArchiveQueueMax,
.val = PARSE_OPTION_FLAG | cfgOptArchiveQueueMax,
},
{
.name = "archive-timeout",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptArchiveTimeout,
.val = PARSE_OPTION_FLAG | cfgOptArchiveTimeout,
},
{
.name = "backup-cmd",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptBackupCmd,
.val = PARSE_OPTION_FLAG | cfgOptBackupCmd,
},
{
.name = "backup-config",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptBackupConfig,
.val = PARSE_OPTION_FLAG | cfgOptBackupConfig,
},
{
.name = "backup-host",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptBackupHost,
.val = PARSE_OPTION_FLAG | cfgOptBackupHost,
},
{
.name = "backup-ssh-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptBackupSshPort,
.val = PARSE_OPTION_FLAG | cfgOptBackupSshPort,
},
{
.name = "backup-standby",
.val = PARSE_OPTION_OFFSET + cfgOptBackupStandby,
.val = PARSE_OPTION_FLAG | cfgOptBackupStandby,
},
{
.name = "no-backup-standby",
.val = PARSE_OPTION_OFFSET + cfgOptBackupStandby,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptBackupStandby,
},
{
.name = "backup-user",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptBackupUser,
.val = PARSE_OPTION_FLAG | cfgOptBackupUser,
},
{
.name = "buffer-size",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptBufferSize,
.val = PARSE_OPTION_FLAG | cfgOptBufferSize,
},
{
.name = "checksum-page",
.val = PARSE_OPTION_OFFSET + cfgOptChecksumPage,
.val = PARSE_OPTION_FLAG | cfgOptChecksumPage,
},
{
.name = "no-checksum-page",
.val = PARSE_OPTION_OFFSET + cfgOptChecksumPage,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptChecksumPage,
},
{
.name = "cmd-ssh",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptCmdSsh,
.val = PARSE_OPTION_FLAG | cfgOptCmdSsh,
},
{
.name = "command",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptCommand,
.val = PARSE_OPTION_FLAG | cfgOptCommand,
},
{
.name = "compress",
.val = PARSE_OPTION_OFFSET + cfgOptCompress,
.val = PARSE_OPTION_FLAG | cfgOptCompress,
},
{
.name = "no-compress",
.val = PARSE_OPTION_OFFSET + cfgOptCompress,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptCompress,
},
{
.name = "compress-level",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptCompressLevel,
.val = PARSE_OPTION_FLAG | cfgOptCompressLevel,
},
{
.name = "compress-level-network",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptCompressLevelNetwork,
.val = PARSE_OPTION_FLAG | cfgOptCompressLevelNetwork,
},
{
.name = "config",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptConfig,
.val = PARSE_OPTION_FLAG | cfgOptConfig,
},
{
.name = "no-config",
.val = PARSE_OPTION_OFFSET + cfgOptConfig,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptConfig,
},
{
.name = "db-cmd",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbCmd,
.val = PARSE_OPTION_FLAG | cfgOptDbCmd,
},
{
.name = "db1-cmd",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbCmd,
.val = PARSE_OPTION_FLAG | cfgOptDbCmd,
},
{
.name = "db2-cmd",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbCmd + 1,
.val = PARSE_OPTION_FLAG | (cfgOptDbCmd + 1),
},
{
.name = "db3-cmd",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbCmd + 2,
.val = PARSE_OPTION_FLAG | (cfgOptDbCmd + 2),
},
{
.name = "db4-cmd",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbCmd + 3,
.val = PARSE_OPTION_FLAG | (cfgOptDbCmd + 3),
},
{
.name = "db5-cmd",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbCmd + 4,
.val = PARSE_OPTION_FLAG | (cfgOptDbCmd + 4),
},
{
.name = "db6-cmd",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbCmd + 5,
.val = PARSE_OPTION_FLAG | (cfgOptDbCmd + 5),
},
{
.name = "db7-cmd",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbCmd + 6,
.val = PARSE_OPTION_FLAG | (cfgOptDbCmd + 6),
},
{
.name = "db8-cmd",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbCmd + 7,
.val = PARSE_OPTION_FLAG | (cfgOptDbCmd + 7),
},
{
.name = "db-config",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbConfig,
.val = PARSE_OPTION_FLAG | cfgOptDbConfig,
},
{
.name = "db1-config",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbConfig,
.val = PARSE_OPTION_FLAG | cfgOptDbConfig,
},
{
.name = "db2-config",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbConfig + 1,
.val = PARSE_OPTION_FLAG | (cfgOptDbConfig + 1),
},
{
.name = "db3-config",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbConfig + 2,
.val = PARSE_OPTION_FLAG | (cfgOptDbConfig + 2),
},
{
.name = "db4-config",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbConfig + 3,
.val = PARSE_OPTION_FLAG | (cfgOptDbConfig + 3),
},
{
.name = "db5-config",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbConfig + 4,
.val = PARSE_OPTION_FLAG | (cfgOptDbConfig + 4),
},
{
.name = "db6-config",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbConfig + 5,
.val = PARSE_OPTION_FLAG | (cfgOptDbConfig + 5),
},
{
.name = "db7-config",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbConfig + 6,
.val = PARSE_OPTION_FLAG | (cfgOptDbConfig + 6),
},
{
.name = "db8-config",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbConfig + 7,
.val = PARSE_OPTION_FLAG | (cfgOptDbConfig + 7),
},
{
.name = "db-host",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbHost,
.val = PARSE_OPTION_FLAG | cfgOptDbHost,
},
{
.name = "db1-host",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbHost,
.val = PARSE_OPTION_FLAG | cfgOptDbHost,
},
{
.name = "db2-host",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbHost + 1,
.val = PARSE_OPTION_FLAG | (cfgOptDbHost + 1),
},
{
.name = "db3-host",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbHost + 2,
.val = PARSE_OPTION_FLAG | (cfgOptDbHost + 2),
},
{
.name = "db4-host",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbHost + 3,
.val = PARSE_OPTION_FLAG | (cfgOptDbHost + 3),
},
{
.name = "db5-host",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbHost + 4,
.val = PARSE_OPTION_FLAG | (cfgOptDbHost + 4),
},
{
.name = "db6-host",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbHost + 5,
.val = PARSE_OPTION_FLAG | (cfgOptDbHost + 5),
},
{
.name = "db7-host",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbHost + 6,
.val = PARSE_OPTION_FLAG | (cfgOptDbHost + 6),
},
{
.name = "db8-host",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbHost + 7,
.val = PARSE_OPTION_FLAG | (cfgOptDbHost + 7),
},
{
.name = "db-include",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbInclude,
.val = PARSE_OPTION_FLAG | cfgOptDbInclude,
},
{
.name = "db-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPath,
.val = PARSE_OPTION_FLAG | cfgOptDbPath,
},
{
.name = "db1-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPath,
.val = PARSE_OPTION_FLAG | cfgOptDbPath,
},
{
.name = "db2-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPath + 1,
.val = PARSE_OPTION_FLAG | (cfgOptDbPath + 1),
},
{
.name = "db3-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPath + 2,
.val = PARSE_OPTION_FLAG | (cfgOptDbPath + 2),
},
{
.name = "db4-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPath + 3,
.val = PARSE_OPTION_FLAG | (cfgOptDbPath + 3),
},
{
.name = "db5-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPath + 4,
.val = PARSE_OPTION_FLAG | (cfgOptDbPath + 4),
},
{
.name = "db6-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPath + 5,
.val = PARSE_OPTION_FLAG | (cfgOptDbPath + 5),
},
{
.name = "db7-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPath + 6,
.val = PARSE_OPTION_FLAG | (cfgOptDbPath + 6),
},
{
.name = "db8-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPath + 7,
.val = PARSE_OPTION_FLAG | (cfgOptDbPath + 7),
},
{
.name = "db-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPort,
.val = PARSE_OPTION_FLAG | cfgOptDbPort,
},
{
.name = "db1-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPort,
.val = PARSE_OPTION_FLAG | cfgOptDbPort,
},
{
.name = "db2-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPort + 1,
.val = PARSE_OPTION_FLAG | (cfgOptDbPort + 1),
},
{
.name = "db3-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPort + 2,
.val = PARSE_OPTION_FLAG | (cfgOptDbPort + 2),
},
{
.name = "db4-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPort + 3,
.val = PARSE_OPTION_FLAG | (cfgOptDbPort + 3),
},
{
.name = "db5-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPort + 4,
.val = PARSE_OPTION_FLAG | (cfgOptDbPort + 4),
},
{
.name = "db6-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPort + 5,
.val = PARSE_OPTION_FLAG | (cfgOptDbPort + 5),
},
{
.name = "db7-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPort + 6,
.val = PARSE_OPTION_FLAG | (cfgOptDbPort + 6),
},
{
.name = "db8-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbPort + 7,
.val = PARSE_OPTION_FLAG | (cfgOptDbPort + 7),
},
{
.name = "db-socket-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSocketPath,
.val = PARSE_OPTION_FLAG | cfgOptDbSocketPath,
},
{
.name = "db1-socket-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSocketPath,
.val = PARSE_OPTION_FLAG | cfgOptDbSocketPath,
},
{
.name = "db2-socket-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSocketPath + 1,
.val = PARSE_OPTION_FLAG | (cfgOptDbSocketPath + 1),
},
{
.name = "db3-socket-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSocketPath + 2,
.val = PARSE_OPTION_FLAG | (cfgOptDbSocketPath + 2),
},
{
.name = "db4-socket-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSocketPath + 3,
.val = PARSE_OPTION_FLAG | (cfgOptDbSocketPath + 3),
},
{
.name = "db5-socket-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSocketPath + 4,
.val = PARSE_OPTION_FLAG | (cfgOptDbSocketPath + 4),
},
{
.name = "db6-socket-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSocketPath + 5,
.val = PARSE_OPTION_FLAG | (cfgOptDbSocketPath + 5),
},
{
.name = "db7-socket-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSocketPath + 6,
.val = PARSE_OPTION_FLAG | (cfgOptDbSocketPath + 6),
},
{
.name = "db8-socket-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSocketPath + 7,
.val = PARSE_OPTION_FLAG | (cfgOptDbSocketPath + 7),
},
{
.name = "db-ssh-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSshPort,
.val = PARSE_OPTION_FLAG | cfgOptDbSshPort,
},
{
.name = "db1-ssh-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSshPort,
.val = PARSE_OPTION_FLAG | cfgOptDbSshPort,
},
{
.name = "db2-ssh-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSshPort + 1,
.val = PARSE_OPTION_FLAG | (cfgOptDbSshPort + 1),
},
{
.name = "db3-ssh-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSshPort + 2,
.val = PARSE_OPTION_FLAG | (cfgOptDbSshPort + 2),
},
{
.name = "db4-ssh-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSshPort + 3,
.val = PARSE_OPTION_FLAG | (cfgOptDbSshPort + 3),
},
{
.name = "db5-ssh-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSshPort + 4,
.val = PARSE_OPTION_FLAG | (cfgOptDbSshPort + 4),
},
{
.name = "db6-ssh-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSshPort + 5,
.val = PARSE_OPTION_FLAG | (cfgOptDbSshPort + 5),
},
{
.name = "db7-ssh-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSshPort + 6,
.val = PARSE_OPTION_FLAG | (cfgOptDbSshPort + 6),
},
{
.name = "db8-ssh-port",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbSshPort + 7,
.val = PARSE_OPTION_FLAG | (cfgOptDbSshPort + 7),
},
{
.name = "db-timeout",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbTimeout,
.val = PARSE_OPTION_FLAG | cfgOptDbTimeout,
},
{
.name = "db-user",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbUser,
.val = PARSE_OPTION_FLAG | cfgOptDbUser,
},
{
.name = "db1-user",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbUser,
.val = PARSE_OPTION_FLAG | cfgOptDbUser,
},
{
.name = "db2-user",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbUser + 1,
.val = PARSE_OPTION_FLAG | (cfgOptDbUser + 1),
},
{
.name = "db3-user",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbUser + 2,
.val = PARSE_OPTION_FLAG | (cfgOptDbUser + 2),
},
{
.name = "db4-user",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbUser + 3,
.val = PARSE_OPTION_FLAG | (cfgOptDbUser + 3),
},
{
.name = "db5-user",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbUser + 4,
.val = PARSE_OPTION_FLAG | (cfgOptDbUser + 4),
},
{
.name = "db6-user",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbUser + 5,
.val = PARSE_OPTION_FLAG | (cfgOptDbUser + 5),
},
{
.name = "db7-user",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbUser + 6,
.val = PARSE_OPTION_FLAG | (cfgOptDbUser + 6),
},
{
.name = "db8-user",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptDbUser + 7,
.val = PARSE_OPTION_FLAG | (cfgOptDbUser + 7),
},
{
.name = "delta",
.val = PARSE_OPTION_OFFSET + cfgOptDelta,
.val = PARSE_OPTION_FLAG | cfgOptDelta,
},
{
.name = "force",
.val = PARSE_OPTION_OFFSET + cfgOptForce,
.val = PARSE_OPTION_FLAG | cfgOptForce,
},
{
.name = "hardlink",
.val = PARSE_OPTION_OFFSET + cfgOptHardlink,
.val = PARSE_OPTION_FLAG | cfgOptHardlink,
},
{
.name = "no-hardlink",
.val = PARSE_OPTION_OFFSET + cfgOptHardlink,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptHardlink,
},
{
.name = "host-id",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptHostId,
.val = PARSE_OPTION_FLAG | cfgOptHostId,
},
{
.name = "link-all",
.val = PARSE_OPTION_OFFSET + cfgOptLinkAll,
.val = PARSE_OPTION_FLAG | cfgOptLinkAll,
},
{
.name = "no-link-all",
.val = PARSE_OPTION_OFFSET + cfgOptLinkAll,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptLinkAll,
},
{
.name = "link-map",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptLinkMap,
.val = PARSE_OPTION_FLAG | cfgOptLinkMap,
},
{
.name = "lock-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptLockPath,
.val = PARSE_OPTION_FLAG | cfgOptLockPath,
},
{
.name = "log-level-console",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptLogLevelConsole,
.val = PARSE_OPTION_FLAG | cfgOptLogLevelConsole,
},
{
.name = "log-level-file",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptLogLevelFile,
.val = PARSE_OPTION_FLAG | cfgOptLogLevelFile,
},
{
.name = "log-level-stderr",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptLogLevelStderr,
.val = PARSE_OPTION_FLAG | cfgOptLogLevelStderr,
},
{
.name = "log-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptLogPath,
.val = PARSE_OPTION_FLAG | cfgOptLogPath,
},
{
.name = "log-timestamp",
.val = PARSE_OPTION_OFFSET + cfgOptLogTimestamp,
.val = PARSE_OPTION_FLAG | cfgOptLogTimestamp,
},
{
.name = "no-log-timestamp",
.val = PARSE_OPTION_OFFSET + cfgOptLogTimestamp,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptLogTimestamp,
},
{
.name = "manifest-save-threshold",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptManifestSaveThreshold,
.val = PARSE_OPTION_FLAG | cfgOptManifestSaveThreshold,
},
{
.name = "neutral-umask",
.val = PARSE_OPTION_OFFSET + cfgOptNeutralUmask,
.val = PARSE_OPTION_FLAG | cfgOptNeutralUmask,
},
{
.name = "no-neutral-umask",
.val = PARSE_OPTION_OFFSET + cfgOptNeutralUmask,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptNeutralUmask,
},
{
.name = "online",
.val = PARSE_OPTION_OFFSET + cfgOptOnline,
.val = PARSE_OPTION_FLAG | cfgOptOnline,
},
{
.name = "no-online",
.val = PARSE_OPTION_OFFSET + cfgOptOnline,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptOnline,
},
{
.name = "output",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptOutput,
.val = PARSE_OPTION_FLAG | cfgOptOutput,
},
{
.name = "process",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptProcess,
.val = PARSE_OPTION_FLAG | cfgOptProcess,
},
{
.name = "process-max",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptProcessMax,
.val = PARSE_OPTION_FLAG | cfgOptProcessMax,
},
{
.name = "protocol-timeout",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptProtocolTimeout,
.val = PARSE_OPTION_FLAG | cfgOptProtocolTimeout,
},
{
.name = "recovery-option",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRecoveryOption,
.val = PARSE_OPTION_FLAG | cfgOptRecoveryOption,
},
{
.name = "repo-cipher-pass",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRepoCipherPass,
.val = PARSE_OPTION_FLAG | cfgOptRepoCipherPass,
},
{
.name = "repo-cipher-type",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRepoCipherType,
.val = PARSE_OPTION_FLAG | cfgOptRepoCipherType,
},
{
.name = "repo-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRepoPath,
.val = PARSE_OPTION_FLAG | cfgOptRepoPath,
},
{
.name = "repo-s3-bucket",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRepoS3Bucket,
.val = PARSE_OPTION_FLAG | cfgOptRepoS3Bucket,
},
{
.name = "repo-s3-ca-file",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRepoS3CaFile,
.val = PARSE_OPTION_FLAG | cfgOptRepoS3CaFile,
},
{
.name = "repo-s3-ca-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRepoS3CaPath,
.val = PARSE_OPTION_FLAG | cfgOptRepoS3CaPath,
},
{
.name = "repo-s3-endpoint",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRepoS3Endpoint,
.val = PARSE_OPTION_FLAG | cfgOptRepoS3Endpoint,
},
{
.name = "repo-s3-host",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRepoS3Host,
.val = PARSE_OPTION_FLAG | cfgOptRepoS3Host,
},
{
.name = "repo-s3-key",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRepoS3Key,
.val = PARSE_OPTION_FLAG | cfgOptRepoS3Key,
},
{
.name = "repo-s3-key-secret",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRepoS3KeySecret,
.val = PARSE_OPTION_FLAG | cfgOptRepoS3KeySecret,
},
{
.name = "repo-s3-region",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRepoS3Region,
.val = PARSE_OPTION_FLAG | cfgOptRepoS3Region,
},
{
.name = "repo-s3-verify-ssl",
.val = PARSE_OPTION_OFFSET + cfgOptRepoS3VerifySsl,
.val = PARSE_OPTION_FLAG | cfgOptRepoS3VerifySsl,
},
{
.name = "no-repo-s3-verify-ssl",
.val = PARSE_OPTION_OFFSET + cfgOptRepoS3VerifySsl,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptRepoS3VerifySsl,
},
{
.name = "repo-type",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRepoType,
.val = PARSE_OPTION_FLAG | cfgOptRepoType,
},
{
.name = "resume",
.val = PARSE_OPTION_OFFSET + cfgOptResume,
.val = PARSE_OPTION_FLAG | cfgOptResume,
},
{
.name = "no-resume",
.val = PARSE_OPTION_OFFSET + cfgOptResume,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptResume,
},
{
.name = "retention-archive",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRetentionArchive,
.val = PARSE_OPTION_FLAG | cfgOptRetentionArchive,
},
{
.name = "retention-archive-type",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRetentionArchiveType,
.val = PARSE_OPTION_FLAG | cfgOptRetentionArchiveType,
},
{
.name = "retention-diff",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRetentionDiff,
.val = PARSE_OPTION_FLAG | cfgOptRetentionDiff,
},
{
.name = "retention-full",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptRetentionFull,
.val = PARSE_OPTION_FLAG | cfgOptRetentionFull,
},
{
.name = "set",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptSet,
.val = PARSE_OPTION_FLAG | cfgOptSet,
},
{
.name = "spool-path",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptSpoolPath,
.val = PARSE_OPTION_FLAG | cfgOptSpoolPath,
},
{
.name = "stanza",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptStanza,
.val = PARSE_OPTION_FLAG | cfgOptStanza,
},
{
.name = "start-fast",
.val = PARSE_OPTION_OFFSET + cfgOptStartFast,
.val = PARSE_OPTION_FLAG | cfgOptStartFast,
},
{
.name = "no-start-fast",
.val = PARSE_OPTION_OFFSET + cfgOptStartFast,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptStartFast,
},
{
.name = "stop-auto",
.val = PARSE_OPTION_OFFSET + cfgOptStopAuto,
.val = PARSE_OPTION_FLAG | cfgOptStopAuto,
},
{
.name = "no-stop-auto",
.val = PARSE_OPTION_OFFSET + cfgOptStopAuto,
.val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptStopAuto,
},
{
.name = "tablespace-map",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptTablespaceMap,
.val = PARSE_OPTION_FLAG | cfgOptTablespaceMap,
},
{
.name = "tablespace-map-all",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptTablespaceMapAll,
.val = PARSE_OPTION_FLAG | cfgOptTablespaceMapAll,
},
{
.name = "target",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptTarget,
.val = PARSE_OPTION_FLAG | cfgOptTarget,
},
{
.name = "target-action",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptTargetAction,
.val = PARSE_OPTION_FLAG | cfgOptTargetAction,
},
{
.name = "target-exclusive",
.val = PARSE_OPTION_OFFSET + cfgOptTargetExclusive,
.val = PARSE_OPTION_FLAG | cfgOptTargetExclusive,
},
{
.name = "target-timeline",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptTargetTimeline,
.val = PARSE_OPTION_FLAG | cfgOptTargetTimeline,
},
{
.name = "test",
.val = PARSE_OPTION_OFFSET + cfgOptTest,
.val = PARSE_OPTION_FLAG | cfgOptTest,
},
{
.name = "test-delay",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptTestDelay,
.val = PARSE_OPTION_FLAG | cfgOptTestDelay,
},
{
.name = "test-point",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptTestPoint,
.val = PARSE_OPTION_FLAG | cfgOptTestPoint,
},
{
.name = "type",
.has_arg = required_argument,
.val = PARSE_OPTION_OFFSET + cfgOptType,
.val = PARSE_OPTION_FLAG | cfgOptType,
},
// Perl option is ignored by normal config parsing
{

View File

@ -1,26 +1,40 @@
/***********************************************************************************************************************************
Command and Option Configuration
Command and Option Parse
***********************************************************************************************************************************/
#include <assert.h>
#include <getopt.h>
#include <string.h>
#include "common/error.h"
#include "config/config.h"
#include "common/memContext.h"
#include "config/parse.h"
/***********************************************************************************************************************************
Include the automatically generated configuration data
***********************************************************************************************************************************/
// Offset the option values so they don't conflict with getopt_long return codes
#define PARSE_OPTION_OFFSET 100000
#define PARSE_OPTION_FLAG (1 << 31)
// Add a flag for negation rather than checking "-no-"
#define PARSE_NEGATE_FLAG (1 << 30)
// Mask to exclude all flags and get at the actual option id (only 12 bits allowed for option id, the rest reserved for flags)
#define PARSE_OPTION_MASK 0xFFF
#include "parse.auto.c"
/***********************************************************************************************************************************
Map command names to ids and vice versa
Parse the command-line arguments and produce preliminary parse data
This function only checks for obvious errors. Dependencies, types, etc, are checked later when data from the config file is
available.
***********************************************************************************************************************************/
void
configParse(int argListSize, const char *argList[])
ParseData *
configParseArg(int argListSize, const char *argList[])
{
// Allocate memory for the parse data
ParseData *parseData = memNew(sizeof(ParseData));
// Reset optind to 1 in case getopt_long has been called before
optind = 1;
@ -31,26 +45,33 @@ configParse(int argListSize, const char *argList[])
bool commandSet = false;
// Parse options
int option;
int optionIdx;
int option; // Code returned by getopt_long
int optionListIdx; // Index of option is list (if an option was returned)
ConfigOption optionId; // Option id extracted from option var
bool negate; // Option is being negated
bool argFound = false; // Track args found to decide on error or help at the end
while ((option = getopt_long(argListSize, (char **)argList, "-", optionList, &optionIdx)) != -1)
while ((option = getopt_long(argListSize, (char **)argList, "-:", optionList, &optionListIdx)) != -1)
{
switch (option)
{
// Perl options that should be ignored
// Add perl options (if any) to the list
case 0:
if (parseData->perlOptionList == NULL)
parseData->perlOptionList = strLstNew();
strLstAdd(parseData->perlOptionList, strNew(optarg));
break;
// Parse parameters 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:
// The first parameter should be the command
// The first argument should be the command
if (!commandSet)
{
// Try getting the command from the valid command list
TRY_BEGIN()
{
cfgCommandSet(cfgCommandId(argList[optind - 1]));
parseData->command = cfgCommandId(argList[optind - 1]);
}
// Assert error means the command does not exist, which is correct for all usages but this one (since we don't
// have any control over what the user passes), so modify the error code and message.
@ -60,19 +81,103 @@ configParse(int argListSize, const char *argList[])
}
TRY_END();
}
// Else implement additional parameters here for more complex commands
// Additioal arguments are command arguments
else
{
if (parseData->commandArgList == NULL)
parseData->commandArgList = strLstNew();
strLstAdd(parseData->commandArgList, strNew(argList[optind - 1]));
}
commandSet = true;
break;
// If the option is unknown generate an error
// If the option is unknown then error
case '?':
THROW(OptionInvalidError, "invalid option '%s'", argList[optind - 1]);
break; // {uncoverable - case statement does not return}
// If the option is missing an argument then error
case ':':
THROW(OptionInvalidError, "option '%s' requires argument", argList[optind - 1]);
break; // {uncoverable - case statement does not return}
// Parse valid option
default:
// Get option id and flags from the option code
optionId = option & PARSE_OPTION_MASK;
negate = option & PARSE_NEGATE_FLAG;
// Make sure the option id is valid
assert(optionId < CFG_OPTION_TOTAL);
// If the the option has not been found yet then set it
if (!parseData->parseOptionList[optionId].found)
{
parseData->parseOptionList[optionId].found = true;
parseData->parseOptionList[optionId].negate = negate;
// Only set the argument if the option requires one
if (optionList[optionListIdx].has_arg == required_argument)
parseData->parseOptionList[optionId].valueList = strLstAdd(strLstNew(), strNew(optarg));
}
else
{
// 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.
if (parseData->parseOptionList[optionId].negate && negate)
THROW(OptionInvalidError, "option '%s' is negated multiple times", cfgOptionName(optionId));
// Don't allow an option to be both set and negated
if (parseData->parseOptionList[optionId].negate != negate)
THROW(OptionInvalidError, "option '%s' cannot be set and negated", cfgOptionName(optionId));
// Error if this option does not allow multiple arguments (!!! IMPLEMENT THIS IN DEFINE.C)
if (!(cfgDefOptionType(cfgOptionDefIdFromId(optionId)) == cfgDefOptTypeHash ||
cfgDefOptionType(cfgOptionDefIdFromId(optionId)) == cfgDefOptTypeList))
{
THROW(OptionInvalidError, "option '%s' cannot have multiple arguments", cfgOptionName(optionId));
}
// Add the argument
strLstAdd(parseData->parseOptionList[optionId].valueList, strNew(optarg));
}
break;
}
// Arg has been found
argFound = true;
}
// Handle command not found
if (!commandSet)
{
// If there are args then error
if (argFound)
THROW(CommandRequiredError, "no command found");
// Otherwise set the comand to help
parseData->command = cfgCmdHelp;
}
// Return the parse data
return parseData;
}
/***********************************************************************************************************************************
Parse the command-line arguments and config file to produce final config data
***********************************************************************************************************************************/
void
configParse(int argListSize, const char *argList[])
{
// Parse the command line
ParseData *parseData = configParseArg(argListSize, argList);
// Set the command
cfgCommandSet(parseData->command);
// Free the parse data
memFree(parseData);
}

View File

@ -4,9 +4,34 @@ Parse Configuration
#ifndef CONFIG_PARSE_H
#define CONFIG_PARSE_H
#include "config/config.h"
/***********************************************************************************************************************************
Struct to hold options parsed from the command line (??? move back to parse.c once perl exec works on full config data)
***********************************************************************************************************************************/
typedef struct ParseOption
{
bool found:1; // Was the option found on the command line?
bool negate:1; // Was the option negated on the command line?
StringList *valueList; // List of values found
} ParseOption;
/***********************************************************************************************************************************
Struct to hold all parsed data (??? move back to parse.c once perl exec works on full config data)
***********************************************************************************************************************************/
typedef struct ParseData
{
ConfigCommand command; // Command found
StringList *perlOptionList; // List of perl options
StringList *commandArgList; // List of command arguments
ParseOption parseOptionList[CFG_OPTION_TOTAL]; // List of parsed options
} ParseData;
ParseData *configParseArg(int argListSize, const char *argList[]);
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
void configParse(int argListSize, char *argList[]);
void configParse(int argListSize, const char *argList[]);
#endif

View File

@ -10,7 +10,7 @@ Main
#include "perl/exec.h"
#include "version.h"
int main(int argListSize, char *argList[])
int main(int argListSize, const char *argList[])
{
TRY_BEGIN()
{

View File

@ -2,7 +2,6 @@
Execute Perl for Legacy Functionality
***********************************************************************************************************************************/
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -12,6 +11,7 @@ Execute Perl for Legacy Functionality
#include "common/error.h"
#include "common/memContext.h"
#include "common/type.h"
#include "config/parse.h"
/***********************************************************************************************************************************
Constants used to build perl options
@ -20,7 +20,6 @@ Constants used to build perl options
#define ENV_EXE "/usr/bin/env"
#define PARAM_PERL_OPTION "perl-option"
#define PARAM_PERL_OPTION_ID 1000
#define PGBACKREST_MODULE PGBACKREST_NAME "::Main"
#define PGBACKREST_MAIN PGBACKREST_MODULE "::main"
@ -28,65 +27,71 @@ Constants used to build perl options
/***********************************************************************************************************************************
Build list of perl options to use for exec
***********************************************************************************************************************************/
StringList *perlCommand(int argListSize, char *argList[])
StringList *perlCommand(int argListSize, const char *argList[])
{
// Setup arg list for perl exec
ParseData *parseData = configParseArg(argListSize, argList);
// Begin arg list for perl exec
StringList *perlArgList = strLstNew();
strLstAdd(perlArgList, strNew(ENV_EXE));
strLstAdd(perlArgList, strNew(PERL_EXE));
// Setup Perl main call
String *mainParamBuffer = strNew("");
// Construct option list to pass to main
String *mainCallParam = strNew("");
// Setup pgbackrest bin
String *binParamBuffer = strNew("");
// Reset optind to 1 in case getopt_long has been called before
optind = 1;
// Don't error on unknown options -- they are expected since we are passing options through to Perl
opterr = false;
// Struct with all valid options
static struct option optionList[] =
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
{
{PARAM_PERL_OPTION, required_argument, NULL, PARAM_PERL_OPTION_ID},
{0, 0, NULL, 0},
};
ParseOption *option = &parseData->parseOptionList[optionId];
// Parse options
int option;
int optionIdx;
while ((option = getopt_long(argListSize, argList, "-", optionList, &optionIdx)) != -1)
{
switch (option)
// If option was found
if (option->found)
{
case 1:
case '?':
strCat(mainParamBuffer, ", ");
strCatFmt(mainParamBuffer, "'%s'", argList[optind - 1]);
break;
case PARAM_PERL_OPTION_ID:
strLstAdd(perlArgList, strNew(optarg));
strCatFmt(binParamBuffer, " --" PARAM_PERL_OPTION "=\"%s\"", optarg);
break;
// If option was negated
if (option->negate)
strCatFmt(mainCallParam, ", '--no-%s\'", cfgOptionName(optionId));
// Else option with no arguments
else if (option->valueList == NULL)
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
// Else options with arguments
else
{
for (unsigned int argIdx = 0; argIdx < strLstSize(option->valueList); argIdx++)
{
strCatFmt(mainCallParam, ", '--%s'", cfgOptionName(optionId));
strCatFmt(mainCallParam, ", '%s'", strPtr(strLstGet(option->valueList, argIdx)));
}
}
}
}
// Finish Perl main call
String *mainBuffer = strNewFmt(
PGBACKREST_MAIN "('%s%s'%s)", argList[0], strPtr(binParamBuffer), strPtr(mainParamBuffer));
// Add command to pass to main
strCatFmt(mainCallParam, ", '%s'", cfgCommandName(parseData->command));
strFree(binParamBuffer);
strFree(mainParamBuffer);
// Add command arguments to pass to main
if (parseData->commandArgList != NULL)
for (unsigned int argIdx = 0; argIdx < strLstSize(parseData->commandArgList); argIdx++)
strCatFmt(mainCallParam, ", '%s'", strPtr(strLstGet(parseData->commandArgList, argIdx)));
// Finish arg list for perl exec
// Construct perl option list to add to bin
String *binPerlOption = strNew("");
if (parseData->perlOptionList != NULL)
for (unsigned int argIdx = 0; argIdx < strLstSize(parseData->perlOptionList); argIdx++)
{
// Add to bin option list
strCatFmt(binPerlOption, " --" PARAM_PERL_OPTION "=\"%s\"", strPtr(strLstGet(parseData->perlOptionList, argIdx)));
// Add to list that will be passed to exec
strLstAdd(perlArgList, strLstGet(parseData->perlOptionList, argIdx));
}
// Construct Perl main call
String *mainCall = strNewFmt(PGBACKREST_MAIN "('%s%s'%s)", argList[0], strPtr(binPerlOption), strPtr(mainCallParam));
// End arg list for perl exec
strLstAdd(perlArgList, strNew("-M" PGBACKREST_MODULE));
strLstAdd(perlArgList, strNew("-e"));
strLstAdd(perlArgList, mainBuffer);
strLstAdd(perlArgList, mainCall);
strLstAdd(perlArgList, NULL);
return perlArgList;

View File

@ -9,7 +9,7 @@ Execute Perl for Legacy Functionality
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
StringList *perlCommand(int argListSize, char *argList[]);
StringList *perlCommand(int argListSize, const char *argList[]);
void perlExec(StringList *perlArgList);
#endif

View File

@ -329,7 +329,7 @@ my $oTestDef =
},
{
&TESTDEF_NAME => 'parse',
&TESTDEF_TOTAL => 1,
&TESTDEF_TOTAL => 2,
&TESTDEF_C => true,
&TESTDEF_COVERAGE =>

View File

@ -168,6 +168,27 @@ Test that a void statement returns and does not throw an error
TRY_END(); \
}
/***********************************************************************************************************************************
Test that a statement does not error and assign it to the specified variable if not
***********************************************************************************************************************************/
#define TEST_ASSIGN(lValue, statement, ...) \
{ \
/* Output test info */ \
TEST_RESULT_INFO(__VA_ARGS__); \
\
TRY_BEGIN() \
{ \
lValue = statement; \
} \
/* Catch any errors */ \
CATCH_ANY() \
{ \
/* No errors were expected so error */ \
THROW(AssertError, "statement '%s' threw error %s, '%s' but result expected", #statement, errorName(), errorMessage()); \
} \
TRY_END(); \
}
/***********************************************************************************************************************************
Macros to ease the use of common data types
***********************************************************************************************************************************/

View File

@ -4,7 +4,10 @@ Test Configuration Parse
#define TEST_BACKREST_EXE "pgbackrest"
#define TEST_COMMAND_ARCHIVE_GET "archive-get"
#define TEST_COMMAND_BACKUP "backup"
#define TEST_COMMAND_HELP "help"
#define TEST_COMMAND_RESTORE "restore"
#define TEST_COMMAND_VERSION "version"
/***********************************************************************************************************************************
@ -13,40 +16,129 @@ Test run
void testRun()
{
// -----------------------------------------------------------------------------------------------------------------------------
if (testBegin("configParse()"))
if (testBegin("configParseArg()"))
{
ParseData *parseData = NULL;
StringList *argList = strLstNew();
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), "exe only");
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), "no command, no args - set help command");
TEST_RESULT_INT(parseData->command, cfgCmdHelp, " command is " TEST_COMMAND_HELP);
// -------------------------------------------------------------------------------------------------------------------------
strLstAdd(argList, strNew("--online"));
TEST_ERROR(configParseArg(strLstSize(argList), strLstPtr(argList)), CommandRequiredError, "no command found");
// -------------------------------------------------------------------------------------------------------------------------
strLstAdd(argList, strNew(TEST_COMMAND_VERSION));
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_VERSION " command");
TEST_RESULT_INT(cfgCommand(), cfgCmdVersion, "command is " TEST_COMMAND_VERSION);
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_VERSION " command");
TEST_RESULT_INT(parseData->command, cfgCmdVersion, " command is " TEST_COMMAND_VERSION);
TEST_RESULT_PTR(parseData->perlOptionList, NULL, " no perl options");
TEST_RESULT_PTR(parseData->commandArgList, NULL, " no command arguments");
// -------------------------------------------------------------------------------------------------------------------------
strLstAdd(argList, strNew("--perl-option=value"));
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), "perl option");
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), "perl option");
TEST_RESULT_STR(strPtr(strLstCat(parseData->perlOptionList, ",")), "value", "check perl option");
// -------------------------------------------------------------------------------------------------------------------------
strLstAdd(argList, strNewFmt("--%s", cfgOptionName(cfgOptDelta)));
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), "delta option");
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), "delta option");
TEST_RESULT_BOOL(parseData->parseOptionList[cfgOptDelta].found, true, " option found");
TEST_RESULT_BOOL(parseData->parseOptionList[cfgOptDelta].negate, false, " option not negated");
TEST_RESULT_PTR(parseData->parseOptionList[cfgOptDelta].valueList, NULL, " no values");
// -------------------------------------------------------------------------------------------------------------------------
strLstAdd(argList, strNew("--" BOGUS_STR));
TEST_ERROR(configParse(strLstSize(argList), strLstPtr(argList)), OptionInvalidError, "invalid option '--BOGUS'");
TEST_ERROR(configParseArg(strLstSize(argList), strLstPtr(argList)), OptionInvalidError, "invalid option '--BOGUS'");
// -------------------------------------------------------------------------------------------------------------------------
argList = strLstNew();
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
strLstAdd(argList, strNew("--no-archive-check"));
strLstAdd(argList, strNew(TEST_COMMAND_HELP));
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_HELP " command");
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_HELP " command");
TEST_RESULT_BOOL(parseData->parseOptionList[cfgOptArchiveCheck].negate, true, " option negated");
// -------------------------------------------------------------------------------------------------------------------------
argList = strLstNew();
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
strLstAdd(argList, strNew(BOGUS_STR));
TEST_ERROR(configParse(strLstSize(argList), strLstPtr(argList)), CommandInvalidError, "invalid command 'BOGUS'");
TEST_ERROR(configParseArg(strLstSize(argList), strLstPtr(argList)), CommandInvalidError, "invalid command 'BOGUS'");
// -------------------------------------------------------------------------------------------------------------------------
argList = strLstNew();
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
strLstAdd(argList, strNew("--no-online"));
strLstAdd(argList, strNew("--no-online"));
TEST_ERROR(
configParseArg(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
"option 'online' is negated multiple times");
// -------------------------------------------------------------------------------------------------------------------------
argList = strLstNew();
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
strLstAdd(argList, strNew("--db-host"));
TEST_ERROR(
configParseArg(strLstSize(argList), strLstPtr(argList)), OptionInvalidError, "option '--db-host' requires argument");
// -------------------------------------------------------------------------------------------------------------------------
argList = strLstNew();
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
strLstAdd(argList, strNew("--config=/etc/config"));
strLstAdd(argList, strNew("--no-config"));
TEST_ERROR(
configParseArg(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
"option 'config' cannot be set and negated");
// -------------------------------------------------------------------------------------------------------------------------
argList = strLstNew();
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
strLstAdd(argList, strNew("--compress-level=3"));
strLstAdd(argList, strNew("--compress-level=3"));
TEST_ERROR(
configParseArg(strLstSize(argList), strLstPtr(argList)), OptionInvalidError,
"option 'compress-level' cannot have multiple arguments");
// -------------------------------------------------------------------------------------------------------------------------
argList = strLstNew();
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
strLstAdd(argList, strNew(TEST_COMMAND_ARCHIVE_GET));
strLstAdd(argList, strNew("000000010000000200000003"));
strLstAdd(argList, strNew("/path/to/wal/RECOVERYWAL"));
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), "command arguments");
TEST_RESULT_STR(
strPtr(strLstCat(parseData->commandArgList, "|")), "000000010000000200000003|/path/to/wal/RECOVERYWAL",
" check command arguments");
// -------------------------------------------------------------------------------------------------------------------------
argList = strLstNew();
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
strLstAdd(argList, strNew("--db-host=db1.test.org"));
strLstAdd(argList, strNew(TEST_COMMAND_BACKUP));
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), "single valid option");
TEST_RESULT_STR(
strPtr(strLstCat(parseData->parseOptionList[cfgOptDbHost].valueList, "|")), "db1.test.org", " check db-host option");
// -------------------------------------------------------------------------------------------------------------------------
argList = strLstNew();
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
strLstAdd(argList, strNew("--link-map=ts1=/path/to/ts1"));
strLstAdd(argList, strNew("--link-map=ts2=/path/to/ts2"));
strLstAdd(argList, strNew(TEST_COMMAND_RESTORE));
TEST_ASSIGN(parseData, configParseArg(strLstSize(argList), strLstPtr(argList)), "multiple valid options");
TEST_RESULT_STR(
strPtr(strLstCat(parseData->parseOptionList[cfgOptLinkMap].valueList, "|")), "ts1=/path/to/ts1|ts2=/path/to/ts2",
" check link-map options");
}
// -----------------------------------------------------------------------------------------------------------------------------
if (testBegin("configParse()"))
{
StringList *argList = strLstNew();
strLstAdd(argList, strNew(TEST_BACKREST_EXE));
strLstAdd(argList, strNew(TEST_COMMAND_HELP));
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList)), TEST_COMMAND_HELP " command");
TEST_RESULT_INT(cfgCommand(), cfgCmdHelp, " command is " TEST_COMMAND_HELP);
}
}

View File

@ -17,46 +17,68 @@ void testRun()
if (testBegin("perlCommand()"))
{
// -------------------------------------------------------------------------------------------------------------------------
char *cmdLineParam[128];
const char *cmdLineParam[128];
int cmdLineParamSize = 0;
cmdLineParam[cmdLineParamSize++] = (char *)TEST_BACKREST_EXE;
cmdLineParam[cmdLineParamSize++] = TEST_BACKREST_EXE;
cmdLineParam[cmdLineParamSize++] = "backup";
TEST_RESULT_STR(
strPtr(strLstCat(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "')|[NULL]", "simple command");
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "', 'backup')|[NULL]", "simple command");
// -------------------------------------------------------------------------------------------------------------------------
cmdLineParam[cmdLineParamSize++] = (char *)"--option";
cmdLineParam[cmdLineParamSize++] = "--compress";
TEST_RESULT_STR(
strPtr(strLstCat(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "', '--option')|[NULL]", "simple option");
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "', '--compress', 'backup')|[NULL]", "simple option");
// -------------------------------------------------------------------------------------------------------------------------
cmdLineParam[cmdLineParamSize++] = (char *)"--option2=value";
cmdLineParam[cmdLineParamSize++] = "--db-host=db1";
TEST_RESULT_STR(
strPtr(strLstCat(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "', '--option', '--option2=value')|[NULL]",
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "', '--compress', '--db1-host', 'db1', 'backup')|[NULL]",
"option with = before value");
// -------------------------------------------------------------------------------------------------------------------------
cmdLineParam[cmdLineParamSize++] = (char *)"--option3";
cmdLineParam[cmdLineParamSize++] = (char *)"value";
cmdLineParam[cmdLineParamSize++] = "--db-user";
cmdLineParam[cmdLineParamSize++] = "postgres";
TEST_RESULT_STR(
strPtr(strLstCat(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN "', '--option', '--option2=value', '--option3', 'value')|[NULL]",
TEST_ENV_EXE "|" TEST_PERL_EXE "|" TEST_PERL_MAIN
"', '--compress', '--db1-host', 'db1', '--db1-user', 'postgres', 'backup')|[NULL]",
"option with space before value");
// -------------------------------------------------------------------------------------------------------------------------
cmdLineParam[cmdLineParamSize++] = (char *)"--perl-option=-I.";
cmdLineParam[cmdLineParamSize++] = "--perl-option=-I.";
TEST_RESULT_STR(
strPtr(strLstCat(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|-I.|" TEST_PERL_MAIN " --perl-option=\"-I.\"', '--option', '--option2=value', "
"'--option3', 'value')|[NULL]",
TEST_ENV_EXE "|" TEST_PERL_EXE "|-I.|" TEST_PERL_MAIN
" --perl-option=\"-I.\"', '--compress', '--db1-host', 'db1', '--db1-user', 'postgres', 'backup')|[NULL]",
"perl option");
// -------------------------------------------------------------------------------------------------------------------------
cmdLineParam[cmdLineParamSize++] = "--no-online";
TEST_RESULT_STR(
strPtr(strLstCat(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|-I.|" TEST_PERL_MAIN
" --perl-option=\"-I.\"', '--compress', '--db1-host', 'db1', '--db1-user', 'postgres', '--no-online',"
" 'backup')|[NULL]",
"perl option");
// -------------------------------------------------------------------------------------------------------------------------
cmdLineParam[cmdLineParamSize++] = "cmdarg1";
TEST_RESULT_STR(
strPtr(strLstCat(perlCommand(cmdLineParamSize, cmdLineParam), "|")),
TEST_ENV_EXE "|" TEST_PERL_EXE "|-I.|" TEST_PERL_MAIN
" --perl-option=\"-I.\"', '--compress', '--db1-host', 'db1', '--db1-user', 'postgres', '--no-online', 'backup',"
" 'cmdarg1')|[NULL]",
"perl option");
}