1 /***********************************************************************************************************************************
2 Exec Configuration
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5
6 #include <string.h>
7
8 #include "common/debug.h"
9 #include "common/log.h"
10 #include "config/config.intern.h"
11 #include "config/exec.h"
12 #include "config/parse.h"
13
14 /**********************************************************************************************************************************/
15 StringList *
cfgExecParam(ConfigCommand commandId,ConfigCommandRole commandRoleId,const KeyValue * optionReplace,bool local,bool quote)16 cfgExecParam(ConfigCommand commandId, ConfigCommandRole commandRoleId, const KeyValue *optionReplace, bool local, bool quote)
17 {
18 FUNCTION_LOG_BEGIN(logLevelTrace);
19 FUNCTION_LOG_PARAM(ENUM, commandId);
20 FUNCTION_LOG_PARAM(ENUM, commandRoleId);
21 FUNCTION_LOG_PARAM(KEY_VALUE, optionReplace);
22 FUNCTION_LOG_PARAM(BOOL, local); // Will the new process be running on the same host?
23 FUNCTION_LOG_PARAM(BOOL, quote); // Do parameters with spaces need to be quoted?
24 FUNCTION_LOG_END();
25
26 StringList *result = NULL;
27
28 MEM_CONTEXT_TEMP_BEGIN()
29 {
30 // Loop though options and add the ones that apply to the specified command
31 result = strLstNew();
32
33 for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
34 {
35 // Skip the option if it is not valid for the original/specified command or if is secure. Also skip repo1-cipher-type
36 // because there's no point of passing it if the other process doesn't have access to repo1-cipher-pass. There is
37 // probably a better way to do this last part...
38 if (!cfgParseOptionValid(commandId, commandRoleId, optionId) || cfgParseOptionSecure(optionId) ||
39 optionId == cfgOptRepoCipherType)
40 {
41 continue;
42 }
43
44 // Loop through option indexes
45 unsigned int optionIdxTotal = cfgOptionGroup(optionId) ? cfgOptionGroupIdxTotal(cfgOptionGroupId(optionId)) : 1;
46
47 for (unsigned int optionIdx = 0; optionIdx < optionIdxTotal; optionIdx++)
48 {
49 // First check for a replacement
50 const Variant *key = VARSTRZ(cfgOptionIdxName(optionId, optionIdx));
51 const Variant *value = NULL;
52 bool exists = false;
53
54 // If an option is requested to be replaced (usually because remote processes do not have access to the config)
55 // then if the option exists, get the new value for replacement
56 if (optionReplace != NULL)
57 {
58 exists = kvKeyExists(optionReplace, key);
59
60 if (exists)
61 value = kvGet(optionReplace, key);
62 }
63
64 // If the key exists but its value is NULL then skip this option
65 if (exists && value == NULL)
66 continue;
67
68 // If no replacement then see if this option is not default
69 if (value == NULL && cfgOptionValid(optionId))
70 {
71 if (cfgOptionIdxNegate(optionId, optionIdx))
72 value = BOOL_FALSE_VAR;
73 else if (cfgOptionIdxSource(optionId, optionIdx) != cfgSourceDefault)
74 value = cfgOptionIdx(optionId, optionIdx);
75 }
76
77 // If the option was reset
78 if (value == NULL && cfgOptionValid(optionId) && cfgOptionIdxReset(optionId, optionIdx))
79 {
80 strLstAdd(result, strNewFmt("--reset-%s", cfgOptionIdxName(optionId, optionIdx)));
81 }
82 // Else format the value if found, even if the option is not valid for the command
83 else if (value != NULL && (!local || exists || cfgOptionIdxSource(optionId, optionIdx) == cfgSourceParam))
84 {
85 if (varType(value) == varTypeBool)
86 {
87 strLstAdd(result, strNewFmt("--%s%s", varBool(value) ? "" : "no-", cfgOptionIdxName(optionId, optionIdx)));
88 }
89 else
90 {
91 StringList *valueList = NULL;
92
93 if (varType(value) == varTypeKeyValue)
94 {
95 valueList = strLstNew();
96
97 const KeyValue *optionKv = varKv(value);
98 const VariantList *keyList = kvKeyList(optionKv);
99
100 for (unsigned int keyIdx = 0; keyIdx < varLstSize(keyList); keyIdx++)
101 {
102 strLstAdd(
103 valueList,
104 strNewFmt(
105 "%s=%s", strZ(varStr(varLstGet(keyList, keyIdx))),
106 strZ(varStrForce(kvGet(optionKv, varLstGet(keyList, keyIdx))))));
107 }
108 }
109 else if (varType(value) == varTypeVariantList)
110 {
111 valueList = strLstNewVarLst(varVarLst(value));
112 }
113 // Else only one value
114 else
115 {
116 valueList = strLstNew();
117 strLstAdd(valueList, cfgOptionDisplayVar(value, cfgParseOptionType(optionId)));
118 }
119
120 // Output options and values
121 for (unsigned int valueListIdx = 0; valueListIdx < strLstSize(valueList); valueListIdx++)
122 {
123 const String *value = strLstGet(valueList, valueListIdx);
124
125 if (quote && strchr(strZ(value), ' ') != NULL)
126 value = strNewFmt("\"%s\"", strZ(value));
127
128 strLstAdd(result, strNewFmt("--%s=%s", cfgOptionIdxName(optionId, optionIdx), strZ(value)));
129 }
130 }
131 }
132 }
133 }
134
135 // Add the command
136 strLstAdd(result, cfgParseCommandRoleName(commandId, commandRoleId, COLON_STR));
137
138 // Move list to the prior context
139 strLstMove(result, memContextPrior());
140 }
141 MEM_CONTEXT_TEMP_END();
142
143 FUNCTION_LOG_RETURN(STRING_LIST, result);
144 }
145