MINOR: tools: support for word expansion of environment in parse_line

Allow the syntax "${...[*]}" to expand an environment variable
containing several values separated by spaces as individual arguments. A
new flag PARSE_OPT_WORD_EXPAND has been added to toggle this feature on
parse_line invocation. In case of an invalid syntax, a new error
PARSE_ERR_WRONG_EXPAND will be triggered.

This feature has been asked on the github issue #165.
This commit is contained in:
Amaury Denoyelle 2020-10-01 14:32:35 +02:00 committed by Willy Tarreau
parent ac32b4b98c
commit fa41cb6792
4 changed files with 50 additions and 4 deletions

View File

@ -475,7 +475,10 @@ interpreted only within double quotes. Variables are expanded during the
configuration parsing. Variable names must be preceded by a dollar ("$") and
optionally enclosed with braces ("{}") similarly to what is done in Bourne
shell. Variable names can contain alphanumerical characters or the character
underscore ("_") but should not start with a digit.
underscore ("_") but should not start with a digit. If the variable contains a
list of several values separated by spaces, it can be expanded as individual
arguments by enclosing the variable with braces and appending the suffix '[*]'
before the closing brace.
Example:

View File

@ -57,6 +57,7 @@
#define PARSE_OPT_DQUOTE 0x00000008 // '"' encloses a string
#define PARSE_OPT_ENV 0x00000010 // '$' is followed by environment variables
#define PARSE_OPT_INPLACE 0x00000020 // parse and tokenize in-place (src == dst)
#define PARSE_OPT_WORD_EXPAND 0x00000040 // '[*]' suffix to expand an environment variable as several individual arguments
/* return error flags from parse_line() */
#define PARSE_ERR_TOOLARGE 0x00000001 // result is too large for initial outlen
@ -66,6 +67,7 @@
#define PARSE_ERR_HEX 0x00000010 // unparsable hex sequence (at errptr)
#define PARSE_ERR_VARNAME 0x00000020 // invalid variable name (at errptr)
#define PARSE_ERR_OVERLAP 0x00000040 // output overlaps with input, need to allocate
#define PARSE_ERR_WRONG_EXPAND 0x00000080 // unparsable word expansion sequence
/* special return values for the time parser (parse_time_err()) */
#define PARSE_TIME_UNDER ((char *)1)

View File

@ -1908,7 +1908,8 @@ next_line:
outlen = outlinesize;
err = parse_line(line, outline, &outlen, args, &arg,
PARSE_OPT_ENV | PARSE_OPT_DQUOTE | PARSE_OPT_SQUOTE |
PARSE_OPT_BKSLASH | PARSE_OPT_SHARP, &errptr);
PARSE_OPT_BKSLASH | PARSE_OPT_SHARP | PARSE_OPT_WORD_EXPAND,
&errptr);
if (err & PARSE_ERR_QUOTE) {
size_t newpos = sanitize_for_printing(line, errptr - line, 80);
@ -1950,6 +1951,16 @@ next_line:
goto next_line;
}
if (err & PARSE_ERR_WRONG_EXPAND) {
size_t newpos = sanitize_for_printing(line, errptr - line, 80);
ha_alert("parsing [%s:%d]: truncated or invalid word expansion sequence at position %d:\n"
" %s\n %*s\n", file, linenum, (int)(errptr-thisline+1), line, (int)(newpos+1), "^");
err_code |= ERR_ALERT | ERR_FATAL;
fatal++;
goto next_line;
}
if (err & (PARSE_ERR_TOOLARGE|PARSE_ERR_OVERLAP)) {
outlinesize = (outlen + 1023) & -1024;
outline = realloc(outline, outlinesize);

View File

@ -4911,6 +4911,7 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg
{
char *quote = NULL;
char *brace = NULL;
char *word_expand = NULL;
unsigned char hex1, hex2;
size_t outmax = *outlen;
int argsmax = *nbargs - 1;
@ -5089,6 +5090,19 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg
value = getenv(var_name);
*in = save_char;
/* support for '[*]' sequence to force word expansion,
* only available inside braces */
if (*in == '[' && brace && (opts & PARSE_OPT_WORD_EXPAND)) {
word_expand = in++;
if (*in++ != '*' || *in++ != ']') {
err |= PARSE_ERR_WRONG_EXPAND;
if (errptr)
*errptr = word_expand;
goto leave;
}
}
if (brace) {
if (*in != '}') {
/* unmatched brace */
@ -5102,9 +5116,25 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg
}
if (value) {
while (*value)
EMIT_CHAR(*value++);
while (*value) {
/* expand as individual parameters on a space character */
if (word_expand && isspace(*value)) {
EMIT_CHAR(0);
++arg;
if (arg < argsmax)
args[arg] = out + outpos;
else
err |= PARSE_ERR_TOOMANY;
/* skip consecutive spaces */
while (isspace(*++value))
;
} else {
EMIT_CHAR(*value++);
}
}
}
word_expand = NULL;
}
else {
/* any other regular char */