From 3dca1af064e3ac25be7deeff1aca9f41ea935358 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Wed, 4 Oct 2017 05:14:00 +0000 Subject: [PATCH] implement lxc_string_split_quoted lxc_string_split_quoted() splits a string on spaces, but keeps groups in single or double qoutes together. In other words, generally what we'd want for argv behavior. Switch lxc-execute to use this for lxc.execute.cmd. Switch lxc-oci template to put the lxc.execute.cmd inside single quotes, because parse_line() will eat those. If we don't do that, then if we have lxc.execute.cmd = /bin/echo "hello, world", then the last double quote will disappear. Signed-off-by: Serge Hallyn --- src/lxc/tools/lxc_execute.c | 5 +-- src/lxc/utils.c | 68 +++++++++++++++++++++++++++++++++++++ src/lxc/utils.h | 1 + templates/lxc-oci.in | 2 +- 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/lxc/tools/lxc_execute.c b/src/lxc/tools/lxc_execute.c index f69ab6a51..234591c47 100644 --- a/src/lxc/tools/lxc_execute.c +++ b/src/lxc/tools/lxc_execute.c @@ -99,10 +99,7 @@ static bool set_argv(struct lxc_conf *conf, struct lxc_arguments *args) if (!conf->execute_cmd) return false; - /* TODO - - we should honor '"' etc; This seems worth a new helper in utils.c. - */ - components = lxc_string_split(conf->execute_cmd, ' '); + components = lxc_string_split_quoted(conf->execute_cmd); if (!components) return false; diff --git a/src/lxc/utils.c b/src/lxc/utils.c index e6a44a516..c9a60979a 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -816,6 +816,74 @@ error_out: return NULL; } +static bool complete_word(char ***result, char *start, char *end, size_t *cap, size_t *cnt) +{ + int r; + + r = lxc_grow_array((void ***)result, cap, 2 + *cnt, 16); + if (r < 0) + return false; + (*result)[*cnt] = strndup(start, end - start); + if (!(*result)[*cnt]) + return false; + (*cnt)++; + + return true; +} + +/* + * Given a a string 'one two "three four"', split into three words, + * one, two, and "three four" + */ +char **lxc_string_split_quoted(char *string) +{ + char *nextword = string, *p, state; + char **result = NULL; + size_t result_capacity = 0; + size_t result_count = 0; + + if (!string || !*string) + return calloc(1, sizeof(char *)); + + // TODO I'm *not* handling escaped quote + state = ' '; + for (p = string; *p; p++) { + switch(state) { + case ' ': + if (isspace(*p)) + continue; + else if (*p == '"' || *p == '\'') { + nextword = p; + state = *p; + continue; + } + nextword = p; + state = 'a'; + continue; + case 'a': + if (isspace(*p)) { + complete_word(&result, nextword, p, &result_capacity, &result_count); + state = ' '; + continue; + } + continue; + case '"': + case '\'': + if (*p == state) { + complete_word(&result, nextword+1, p, &result_capacity, &result_count); + state = ' '; + continue; + } + continue; + } + } + + if (state == 'a') + complete_word(&result, nextword, p, &result_capacity, &result_count); + + return realloc(result, (result_count + 1) * sizeof(char *)); +} + char **lxc_string_split_and_trim(const char *string, char _sep) { char *token, *str, *saveptr = NULL; diff --git a/src/lxc/utils.h b/src/lxc/utils.h index e83ed49eb..833ec4416 100644 --- a/src/lxc/utils.h +++ b/src/lxc/utils.h @@ -292,6 +292,7 @@ extern bool lxc_string_in_list(const char *needle, const char *haystack, char sep); extern char **lxc_string_split(const char *string, char sep); extern char **lxc_string_split_and_trim(const char *string, char sep); +extern char **lxc_string_split_quoted(char *string); /* Append string to NULL-terminated string array. */ extern int lxc_append_string(char ***list, char *entry); diff --git a/templates/lxc-oci.in b/templates/lxc-oci.in index f715125f7..c2cfb351a 100755 --- a/templates/lxc-oci.in +++ b/templates/lxc-oci.in @@ -197,7 +197,7 @@ entrypoint=$(getep ${DOWNLOAD_TEMP} latest) rm -rf "${LXC_ROOTFS}.tmp" LXC_CONF_FILE="${LXC_PATH}/config" -echo "lxc.execute.cmd = ${entrypoint}" >> "${LXC_CONF_FILE}" +echo "lxc.execute.cmd = '${entrypoint}'" >> "${LXC_CONF_FILE}" echo "lxc.mount.auto = proc:mixed sys:mixed cgroup:mixed" >> "${LXC_CONF_FILE}" echo "lxc.uts.name = ${LXC_NAME}" >> ${LXC_PATH}/config -- 2.47.2