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