2018-01-17 09:15:51 -05:00
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Common Command Routines
|
|
|
|
***********************************************************************************************************************************/
|
2019-04-26 08:08:23 -04:00
|
|
|
#include "build.auto.h"
|
|
|
|
|
2018-05-18 12:03:39 -04:00
|
|
|
#include <inttypes.h>
|
2018-01-17 09:15:51 -05:00
|
|
|
#include <string.h>
|
|
|
|
|
2018-05-18 11:57:32 -04:00
|
|
|
#include "common/debug.h"
|
2018-01-17 09:15:51 -05:00
|
|
|
#include "common/log.h"
|
|
|
|
#include "common/memContext.h"
|
2020-08-20 14:04:26 -04:00
|
|
|
#include "common/stat.h"
|
2018-05-18 12:03:39 -04:00
|
|
|
#include "common/time.h"
|
2020-08-20 14:04:26 -04:00
|
|
|
#include "common/type/json.h"
|
2020-11-23 15:55:46 -05:00
|
|
|
#include "config/config.intern.h"
|
2020-12-17 09:32:31 -05:00
|
|
|
#include "config/parse.h"
|
2018-01-17 09:15:51 -05:00
|
|
|
#include "version.h"
|
|
|
|
|
2018-05-18 12:03:39 -04:00
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Track time command started
|
|
|
|
***********************************************************************************************************************************/
|
|
|
|
static TimeMSec timeBegin;
|
2020-08-20 14:11:40 -04:00
|
|
|
static String *cmdOptionStr;
|
2018-05-18 12:03:39 -04:00
|
|
|
|
2020-04-03 18:01:28 -04:00
|
|
|
/**********************************************************************************************************************************/
|
2018-05-18 12:03:39 -04:00
|
|
|
void
|
2018-08-03 19:19:14 -04:00
|
|
|
cmdInit(void)
|
2018-05-18 12:03:39 -04:00
|
|
|
{
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_VOID(logLevelTrace);
|
2018-05-18 12:03:39 -04:00
|
|
|
|
|
|
|
timeBegin = timeMSec();
|
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_RETURN_VOID();
|
2018-05-18 12:03:39 -04:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:01:28 -04:00
|
|
|
/**********************************************************************************************************************************/
|
2020-08-20 14:11:40 -04:00
|
|
|
const String *
|
|
|
|
cmdOption(void)
|
2018-01-17 09:15:51 -05:00
|
|
|
{
|
2020-08-20 14:11:40 -04:00
|
|
|
FUNCTION_TEST_VOID();
|
2018-05-18 11:57:32 -04:00
|
|
|
|
2020-08-20 14:11:40 -04:00
|
|
|
if (cmdOptionStr == NULL)
|
2018-03-12 10:55:58 -04:00
|
|
|
{
|
2020-08-20 14:11:40 -04:00
|
|
|
MEM_CONTEXT_BEGIN(memContextTop())
|
2018-01-17 09:15:51 -05:00
|
|
|
{
|
2020-08-20 14:11:40 -04:00
|
|
|
cmdOptionStr = strNew("");
|
2018-01-17 09:15:51 -05:00
|
|
|
|
2020-08-20 14:11:40 -04:00
|
|
|
MEM_CONTEXT_TEMP_BEGIN()
|
2018-01-17 09:15:51 -05:00
|
|
|
{
|
2018-04-17 18:47:14 -04:00
|
|
|
// Add command parameters if they exist
|
|
|
|
const StringList *commandParamList = cfgCommandParam();
|
|
|
|
|
2021-01-29 14:27:56 -05:00
|
|
|
if (!strLstEmpty(commandParamList))
|
2018-04-17 18:47:14 -04:00
|
|
|
{
|
2020-08-20 14:11:40 -04:00
|
|
|
strCatFmt(cmdOptionStr, " [");
|
2018-04-17 18:47:14 -04:00
|
|
|
|
|
|
|
for (unsigned int commandParamIdx = 0; commandParamIdx < strLstSize(commandParamList); commandParamIdx++)
|
|
|
|
{
|
|
|
|
const String *commandParam = strLstGet(commandParamList, commandParamIdx);
|
|
|
|
|
|
|
|
if (commandParamIdx != 0)
|
2020-08-20 14:11:40 -04:00
|
|
|
strCatFmt(cmdOptionStr, ", ");
|
2018-04-17 18:47:14 -04:00
|
|
|
|
2020-07-30 07:49:06 -04:00
|
|
|
if (strchr(strZ(commandParam), ' ') != NULL)
|
|
|
|
commandParam = strNewFmt("\"%s\"", strZ(commandParam));
|
2018-04-17 18:47:14 -04:00
|
|
|
|
2020-08-20 14:11:40 -04:00
|
|
|
strCat(cmdOptionStr, commandParam);
|
2018-04-17 18:47:14 -04:00
|
|
|
}
|
|
|
|
|
2020-08-20 14:11:40 -04:00
|
|
|
strCatFmt(cmdOptionStr, "]");
|
2018-04-17 18:47:14 -04:00
|
|
|
}
|
|
|
|
|
2018-04-12 20:42:26 -04:00
|
|
|
// Loop though options and add the ones that are interesting
|
|
|
|
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
|
2018-01-17 09:15:51 -05:00
|
|
|
{
|
2019-11-14 16:48:41 -05:00
|
|
|
// Skip the option if not valid for this command. Generally only one command runs at a time, but sometimes
|
|
|
|
// commands are chained together (e.g. backup and expire) and the second command may not use all the options of
|
|
|
|
// the first command. Displaying them is harmless but might cause confusion.
|
2020-12-28 09:43:23 -05:00
|
|
|
if (!cfgOptionValid(optionId) || !cfgParseOptionValid(cfgCommand(), cfgCommandRole(), optionId))
|
2018-04-12 20:42:26 -04:00
|
|
|
continue;
|
|
|
|
|
2020-11-23 15:55:46 -05:00
|
|
|
// Loop through option indexes
|
|
|
|
unsigned int optionIdxTotal = cfgOptionGroup(optionId) ? cfgOptionGroupIdxTotal(cfgOptionGroupId(optionId)) : 1;
|
|
|
|
|
|
|
|
for (unsigned int optionIdx = 0; optionIdx < optionIdxTotal; optionIdx++)
|
2018-01-17 09:15:51 -05:00
|
|
|
{
|
2020-11-23 15:55:46 -05:00
|
|
|
// If option was negated
|
|
|
|
if (cfgOptionIdxNegate(optionId, optionIdx))
|
|
|
|
strCatFmt(cmdOptionStr, " --no-%s", cfgOptionIdxName(optionId, optionIdx));
|
|
|
|
// If option was reset
|
|
|
|
else if (cfgOptionIdxReset(optionId, optionIdx))
|
|
|
|
strCatFmt(cmdOptionStr, " --reset-%s", cfgOptionIdxName(optionId, optionIdx));
|
|
|
|
// Else not default
|
|
|
|
else if (cfgOptionIdxSource(optionId, optionIdx) != cfgSourceDefault)
|
2018-03-12 10:55:58 -04:00
|
|
|
{
|
2020-11-23 15:55:46 -05:00
|
|
|
// Don't show redacted options
|
2020-12-17 09:32:31 -05:00
|
|
|
if (cfgParseOptionSecure(optionId))
|
2020-11-23 15:55:46 -05:00
|
|
|
strCatFmt(cmdOptionStr, " --%s=<redacted>", cfgOptionIdxName(optionId, optionIdx));
|
|
|
|
// Output boolean option
|
2020-12-17 09:32:31 -05:00
|
|
|
else if (cfgParseOptionType(optionId) == cfgOptTypeBoolean)
|
2020-11-23 15:55:46 -05:00
|
|
|
strCatFmt(cmdOptionStr, " --%s", cfgOptionIdxName(optionId, optionIdx));
|
|
|
|
// Output other options
|
|
|
|
else
|
2018-03-12 10:55:58 -04:00
|
|
|
{
|
2020-11-23 15:55:46 -05:00
|
|
|
StringList *valueList = NULL;
|
2018-04-12 20:42:26 -04:00
|
|
|
|
2020-11-23 15:55:46 -05:00
|
|
|
// Generate the values of hash options
|
2020-12-17 09:32:31 -05:00
|
|
|
if (cfgParseOptionType(optionId) == cfgOptTypeHash)
|
2018-04-12 20:42:26 -04:00
|
|
|
{
|
2020-11-23 15:55:46 -05:00
|
|
|
valueList = strLstNew();
|
|
|
|
|
|
|
|
const KeyValue *optionKv = cfgOptionIdxKv(optionId, optionIdx);
|
|
|
|
const VariantList *keyList = kvKeyList(optionKv);
|
|
|
|
|
|
|
|
for (unsigned int keyIdx = 0; keyIdx < varLstSize(keyList); keyIdx++)
|
|
|
|
{
|
|
|
|
strLstAdd(
|
|
|
|
valueList,
|
|
|
|
strNewFmt(
|
|
|
|
"%s=%s", strZ(varStr(varLstGet(keyList, keyIdx))),
|
|
|
|
strZ(varStrForce(kvGet(optionKv, varLstGet(keyList, keyIdx))))));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Generate values for list options
|
2020-12-17 09:32:31 -05:00
|
|
|
else if (cfgParseOptionType(optionId) == cfgOptTypeList)
|
2020-11-23 15:55:46 -05:00
|
|
|
{
|
|
|
|
valueList = strLstNewVarLst(cfgOptionIdxLst(optionId, optionIdx));
|
|
|
|
}
|
2020-12-09 08:59:51 -05:00
|
|
|
// Generate time value
|
2020-12-17 09:32:31 -05:00
|
|
|
else if (cfgParseOptionType(optionId) == cfgOptTypeTime)
|
2020-12-09 08:59:51 -05:00
|
|
|
{
|
|
|
|
valueList = strLstNew();
|
2021-01-27 11:50:10 -05:00
|
|
|
strLstAdd(valueList, strNewDbl((double)cfgOptionIdxInt64(optionId, optionIdx) / MSEC_PER_SEC));
|
2020-12-09 08:59:51 -05:00
|
|
|
}
|
2020-11-23 15:55:46 -05:00
|
|
|
// Else only one value
|
|
|
|
else
|
|
|
|
{
|
|
|
|
valueList = strLstNew();
|
|
|
|
strLstAdd(valueList, varStrForce(cfgOptionIdx(optionId, optionIdx)));
|
2018-04-12 20:42:26 -04:00
|
|
|
}
|
2018-01-17 09:15:51 -05:00
|
|
|
|
2020-11-23 15:55:46 -05:00
|
|
|
// Output options and values
|
|
|
|
for (unsigned int valueListIdx = 0; valueListIdx < strLstSize(valueList); valueListIdx++)
|
|
|
|
{
|
|
|
|
const String *value = strLstGet(valueList, valueListIdx);
|
2018-03-12 10:55:58 -04:00
|
|
|
|
2020-11-23 15:55:46 -05:00
|
|
|
strCatFmt(cmdOptionStr, " --%s", cfgOptionIdxName(optionId, optionIdx));
|
2018-03-12 10:55:58 -04:00
|
|
|
|
2020-11-23 15:55:46 -05:00
|
|
|
if (strchr(strZ(value), ' ') != NULL)
|
|
|
|
value = strNewFmt("\"%s\"", strZ(value));
|
2018-03-12 10:55:58 -04:00
|
|
|
|
2020-11-23 15:55:46 -05:00
|
|
|
strCatFmt(cmdOptionStr, "=%s", strZ(value));
|
|
|
|
}
|
2018-04-12 20:42:26 -04:00
|
|
|
}
|
2018-03-12 10:55:58 -04:00
|
|
|
}
|
2018-01-17 09:15:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-20 14:11:40 -04:00
|
|
|
MEM_CONTEXT_TEMP_END();
|
|
|
|
}
|
|
|
|
MEM_CONTEXT_END();
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNCTION_TEST_RETURN(cmdOptionStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************************************************************************/
|
|
|
|
void
|
2020-08-20 14:16:36 -04:00
|
|
|
cmdBegin(void)
|
2020-08-20 14:11:40 -04:00
|
|
|
{
|
2020-08-20 14:16:36 -04:00
|
|
|
FUNCTION_LOG_VOID(logLevelTrace);
|
2020-08-20 14:11:40 -04:00
|
|
|
|
|
|
|
ASSERT(cfgCommand() != cfgCmdNone);
|
|
|
|
|
|
|
|
// This is fairly expensive log message to generate so skip it if it won't be output
|
|
|
|
if (logAny(cfgLogLevelDefault()))
|
|
|
|
{
|
|
|
|
MEM_CONTEXT_TEMP_BEGIN()
|
|
|
|
{
|
|
|
|
// Basic info on command start
|
|
|
|
String *info = strNewFmt("%s command begin", strZ(cfgCommandRoleName()));
|
|
|
|
|
2020-08-20 14:16:36 -04:00
|
|
|
// Free the old option string if it exists. This is needed when more than one command is run in a row so an option
|
|
|
|
// string gets created for the new command.
|
|
|
|
strFree(cmdOptionStr);
|
|
|
|
cmdOptionStr = NULL;
|
2020-08-20 14:11:40 -04:00
|
|
|
|
2020-08-20 14:16:36 -04:00
|
|
|
// Add version and options
|
|
|
|
strCatFmt(info, " %s:%s", PROJECT_VERSION, strZ(cmdOption()));
|
2018-01-17 09:15:51 -05:00
|
|
|
|
2020-07-30 07:49:06 -04:00
|
|
|
LOG(cfgLogLevelDefault(), 0, strZ(info));
|
2018-03-12 10:55:58 -04:00
|
|
|
}
|
|
|
|
MEM_CONTEXT_TEMP_END();
|
2018-01-17 09:15:51 -05:00
|
|
|
}
|
2018-05-18 11:57:32 -04:00
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_RETURN_VOID();
|
2018-01-17 09:15:51 -05:00
|
|
|
}
|
|
|
|
|
2020-04-03 18:01:28 -04:00
|
|
|
/**********************************************************************************************************************************/
|
2018-01-31 18:22:25 -05:00
|
|
|
void
|
2018-04-12 20:42:26 -04:00
|
|
|
cmdEnd(int code, const String *errorMessage)
|
2018-01-17 09:15:51 -05:00
|
|
|
{
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
|
|
FUNCTION_LOG_PARAM(INT, code);
|
|
|
|
FUNCTION_LOG_PARAM(STRING, errorMessage);
|
|
|
|
FUNCTION_LOG_END();
|
2018-05-18 11:57:32 -04:00
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
ASSERT(cfgCommand() != cfgCmdNone);
|
2018-03-12 10:55:58 -04:00
|
|
|
|
|
|
|
// Skip this log message if it won't be output. It's not too expensive but since we skipped cmdBegin(), may as well.
|
2019-05-11 18:20:57 -04:00
|
|
|
if (logAny(cfgLogLevelDefault()))
|
2018-01-17 09:15:51 -05:00
|
|
|
{
|
2018-03-12 10:55:58 -04:00
|
|
|
MEM_CONTEXT_TEMP_BEGIN()
|
|
|
|
{
|
2020-08-20 14:04:26 -04:00
|
|
|
// Output statistics if there are any
|
|
|
|
const KeyValue *statKv = statToKv();
|
2020-03-31 12:43:29 -04:00
|
|
|
|
2021-01-29 14:27:56 -05:00
|
|
|
if (!varLstEmpty(kvKeyList(statKv)))
|
2020-08-20 14:04:26 -04:00
|
|
|
LOG_DETAIL_FMT("statistics: %s", strZ(jsonFromKv(statKv)));
|
2019-05-28 09:50:59 -04:00
|
|
|
|
2018-03-12 10:55:58 -04:00
|
|
|
// Basic info on command end
|
2020-07-30 07:49:06 -04:00
|
|
|
String *info = strNewFmt("%s command end: ", strZ(cfgCommandRoleName()));
|
2018-01-17 09:15:51 -05:00
|
|
|
|
2018-09-04 21:46:41 -04:00
|
|
|
if (errorMessage == NULL)
|
2018-05-18 12:03:39 -04:00
|
|
|
{
|
2020-06-24 12:09:24 -04:00
|
|
|
strCatZ(info, "completed successfully");
|
2018-05-18 12:03:39 -04:00
|
|
|
|
2020-10-20 14:54:28 -04:00
|
|
|
if (cfgOptionBool(cfgOptLogTimestamp))
|
2018-05-18 12:03:39 -04:00
|
|
|
strCatFmt(info, " (%" PRIu64 "ms)", timeMSec() - timeBegin);
|
|
|
|
}
|
2018-03-12 10:55:58 -04:00
|
|
|
else
|
2020-06-24 12:09:24 -04:00
|
|
|
strCat(info, errorMessage);
|
2018-01-17 09:15:51 -05:00
|
|
|
|
2020-07-30 07:49:06 -04:00
|
|
|
LOG(cfgLogLevelDefault(), 0, strZ(info));
|
2018-03-12 10:55:58 -04:00
|
|
|
}
|
|
|
|
MEM_CONTEXT_TEMP_END();
|
2018-01-17 09:15:51 -05:00
|
|
|
}
|
2018-05-18 11:57:32 -04:00
|
|
|
|
2018-05-18 12:03:39 -04:00
|
|
|
// Reset timeBegin in case there is another command following this one
|
|
|
|
timeBegin = timeMSec();
|
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_RETURN_VOID();
|
2018-01-17 09:15:51 -05:00
|
|
|
}
|