diff options
author | Thomas Haller <thaller@redhat.com> | 2016-09-23 10:30:57 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2016-09-23 11:59:23 +0200 |
commit | e6ee2fd7637a67ee1af427a8791a2db0492a7768 (patch) | |
tree | 6424af663428bd12c5f10435dbc0d36defa71c92 | |
parent | 78898c4d64a631df7f544397af4575227a713ae5 (diff) | |
download | NetworkManager-th/nmcli-team-config-args-bgo771870.tar.gz |
cli: support explicitly selecting team-config as file or json datath/nmcli-team-config-args-bgo771870
nmcli has a heuristic when setting the team-config to accepting both
a filename or the plain json text.
Add support for two schemes "file://" and "json://" to explicitly
determine whether to read from file or from json.
Also, no longer silently ignore an all-whitespace word. That is an
error (unless you have a file name " ").
Also, no longer replace newlines with space. Don't mangle the input
text at all.
-rw-r--r-- | clients/cli/common.c | 62 | ||||
-rw-r--r-- | man/nmcli.xml | 16 |
2 files changed, 54 insertions, 24 deletions
diff --git a/clients/cli/common.c b/clients/cli/common.c index f8dc523982..d51eda0bd5 100644 --- a/clients/cli/common.c +++ b/clients/cli/common.c @@ -824,10 +824,11 @@ nmc_bond_validate_mode (const char *mode, GError **error) /* * nmc_team_check_config: * @config: file name with team config, or raw team JSON config data - * @out_config: raw team JSON config data (with removed new-line characters) + * @out_config: raw team JSON config data + * The value must be returned with g_free(). * @error: location to store error, or %NUL * - * Check team config from @config parameter and return the checked/sanitized + * Check team config from @config parameter and return the checked * config in @out_config. * * Returns: %TRUE if the config is valid, %FALSE if it is invalid @@ -835,33 +836,58 @@ nmc_bond_validate_mode (const char *mode, GError **error) gboolean nmc_team_check_config (const char *config, char **out_config, GError **error) { - char *contents = NULL; + enum { + _TEAM_CONFIG_TYPE_GUESS, + _TEAM_CONFIG_TYPE_FILE, + _TEAM_CONFIG_TYPE_JSON, + } desired_type = _TEAM_CONFIG_TYPE_GUESS; + const char *filename = NULL; size_t c_len = 0; + gs_free char *config_clone = NULL; *out_config = NULL; - if (!config || strlen (config) == strspn (config, " \t")) + if (!config || !config[0]) return TRUE; - /* 'config' can be either a file name or raw JSON config data */ - if (g_file_test (config, G_FILE_TEST_EXISTS)) - (void) g_file_get_contents (config, &contents, NULL, NULL); - else - contents = g_strdup (config); + if (g_str_has_prefix (config, "file://")) { + config += NM_STRLEN ("file://"); + desired_type = _TEAM_CONFIG_TYPE_FILE; + } else if (g_str_has_prefix (config, "json://")) { + config += NM_STRLEN ("json://"); + desired_type = _TEAM_CONFIG_TYPE_JSON; + } + + if (NM_IN_SET (desired_type, _TEAM_CONFIG_TYPE_FILE, _TEAM_CONFIG_TYPE_GUESS)) { + gs_free char *contents = NULL; - if (contents) { - g_strstrip (contents); - c_len = strlen (contents); + if (!g_file_get_contents (config, &contents, &c_len, NULL)) { + if (desired_type == _TEAM_CONFIG_TYPE_FILE) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("cannot read team config from file '%s'"), + config); + return FALSE; + } + } else { + filename = config; + config = config_clone = g_steal_pointer (&contents); + } } - /* Do a simple validity check */ - if (!contents || !contents[0] || c_len > 100000 || contents[0] != '{' || contents[c_len-1] != '}') { - g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("'%s' is not a valid team configuration or file name."), config); - g_free (contents); + if (!nm_utils_is_json_object (config, NULL)) { + if (filename) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("'%s' does not contain a valid team configuration"), filename); + } else { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("team configuration must be a JSON object")); + } return FALSE; } - *out_config = g_strdelimit (contents, "\r\n", ' '); + + *out_config = (config == config_clone) + ? g_steal_pointer (&config_clone) + : g_strdup (config); return TRUE; } diff --git a/man/nmcli.xml b/man/nmcli.xml index 5a936335c0..965c05f955 100644 --- a/man/nmcli.xml +++ b/man/nmcli.xml @@ -1827,21 +1827,25 @@ It's equivalent of using the <literal>+bond.options 'option=value'</literal> syn </tbody> </tgroup></table> - <table><title>Team options</title><tgroup cols="2"> + <table><title>Team options</title><tgroup cols="3"> <thead> - <row><entry>Alias</entry><entry>Property</entry></row> + <row><entry>Alias</entry><entry>Property</entry><entry>Note</entry></row> </thead> <tbody> - <row><entry align="left">config</entry><entry align="left"><link linkend="nm-settings.property.team.config">team.config</link></entry></row> + <row><entry align="left">config</entry><entry align="left"><link linkend="nm-settings.property.team.config">team.config</link></entry> + <entry align="left">Either a filename or a team configuration in JSON format. To enforce one or the other, the value can be prefixed with "file://" or "json://".</entry> + </row> </tbody> </tgroup></table> - <table><title>Team port options</title><tgroup cols="2"> + <table><title>Team port options</title><tgroup cols="3"> <thead> - <row><entry>Alias</entry><entry>Property</entry></row> + <row><entry>Alias</entry><entry>Property</entry><entry>Note</entry></row> </thead> <tbody> - <row><entry align="left">config</entry><entry align="left"><link linkend="nm-settings.property.team-port.config">team-port.config</link></entry></row> + <row><entry align="left">config</entry><entry align="left"><link linkend="nm-settings.property.team-port.config">team-port.config</link></entry> + <entry align="left">Either a filename or a team configuration in JSON format. To enforce one or the other, the value can be prefixed with "file://" or "json://".</entry> + </row> </tbody> </tgroup></table> |