]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: tools: support for word expansion of environment in parse_line
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 1 Oct 2020 12:32:35 +0000 (14:32 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 1 Oct 2020 15:24:14 +0000 (17:24 +0200)
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.

doc/configuration.txt
include/haproxy/tools-t.h
src/cfgparse.c
src/tools.c

index 87f35e9846ad9dfffec2d26232f85c348905a435..db4a4a7600f90749582df2414c1199525b5e5e35 100644 (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:
 
index b1e72494f44604ed6aa172528ca2e584e3a4116a..34f79bea8a6b9f73d870702c76044b3531c6b5aa 100644 (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)
index 768fea338e6fa8a5ec9948515f51f127f819663d..cb48fef2b028ae1fd956c44d5b01eb01f061a223 100644 (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);
index 53d2486f46ebe8b639c95feae6b5ad214704dfac..c2a96642dd71fbb877a5755cae8e88c797667818 100644 (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 */