diff options
| author | Michael Biebl <biebl@debian.org> | 2017-11-07 00:14:39 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2017-11-07 00:14:39 +0100 |
| commit | 90e8691111889a7b5f3c812f5a41f15a8a058913 (patch) | |
| tree | f101a879eca27c34a9bfa5f3da52266b22539a36 /clients/cli/nmcli.c | |
| parent | bdb6eeb0670658255c2a4c3c501c0a27fa8cfe55 (diff) | |
New upstream version 1.9.90 upstream/1.9.90
Diffstat (limited to 'clients/cli/nmcli.c')
| -rw-r--r-- | clients/cli/nmcli.c | 398 |
1 files changed, 214 insertions, 184 deletions
diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c index b8019403..ee621ca3 100644 --- a/clients/cli/nmcli.c +++ b/clients/cli/nmcli.c @@ -16,11 +16,13 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2010 - 2015 Red Hat, Inc. + * Copyright 2010 - 2017 Red Hat, Inc. */ #include "nm-default.h" +#include "nmcli.h" + #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -32,8 +34,11 @@ #include <readline/readline.h> #include <readline/history.h> +#include "nm-client-utils.h" + +#include "nm-utils/nm-hash-utils.h" + #include "polkit-agent.h" -#include "nmcli.h" #include "utils.h" #include "common.h" #include "connections.h" @@ -49,10 +54,10 @@ #endif /* Global NmCli object */ -// FIXME: Currently, we pass NmCli over in most APIs, but we might refactor -// that and use the global variable directly instead. NmCli nm_cli; +/*****************************************************************************/ + typedef struct { NmCli *nmc; int argc; @@ -66,22 +71,33 @@ struct termios termios_orig; NM_CACHED_QUARK_FCN ("nmcli-error-quark", nmcli_error_quark) static void -complete_field (GHashTable *h, const char *setting, NmcOutputField field[]) +complete_field_setting (GHashTable *h, NMMetaSettingType setting_type) { - int i; + const NMMetaSettingInfoEditor *setting_info = &nm_meta_setting_infos_editor[setting_type]; + guint i; - for (i = 0; field[i].name; i++) { - if (setting) - g_hash_table_add (h, g_strdup_printf ("%s.%s", setting, field[i].name)); - else - g_hash_table_add (h, g_strdup (field[i].name)); + for (i = 0; i < setting_info->properties_num; i++) { + g_hash_table_add (h, g_strdup_printf ("%s.%s", + setting_info->general->setting_name, + setting_info->properties[i]->property_name)); } } static void +complete_field (GHashTable *h, const NmcMetaGenericInfo *const*field) +{ + int i; + + for (i = 0; field[i]; i++) + g_hash_table_add (h, g_strdup (field[i]->name)); +} + +static void complete_one (gpointer key, gpointer value, gpointer user_data) { - const char *prefix = user_data; + const char **option_with_value = user_data; + const char *option = option_with_value[0]; + const char *prefix = option_with_value[1]; const char *name = key; const char *last; @@ -92,78 +108,77 @@ complete_one (gpointer key, gpointer value, gpointer user_data) last = prefix; if ((!*last && !strchr (name, '.')) || matches (last, name)) { + if (option != prefix) { + /* value prefix was not a standalone argument, + * it was part of --option=<value> argument. + * Repeat the part leading to "=". */ + g_print ("%s=", option); + } g_print ("%.*s%s%s\n", (int)(last-prefix), prefix, name, strcmp (last, name) == 0 ? "," : ""); } } static void -complete_fields (const char *prefix) +complete_fields (const char *option, const char *prefix) { - + guint i; GHashTable *h; - - h = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - - complete_field (h, NULL, nmc_fields_ip4_config); - complete_field (h, NULL, nmc_fields_dhcp4_config); - complete_field (h, NULL, nmc_fields_ip6_config); - complete_field (h, NULL, nmc_fields_dhcp6_config); - complete_field (h, NULL, nmc_fields_con_show); - complete_field (h, NULL, nmc_fields_settings_names); - complete_field (h, NULL, nmc_fields_con_active_details_general); - complete_field (h, NULL, nmc_fields_con_active_details_vpn); - complete_field (h, NULL, nmc_fields_con_active_details_groups); - complete_field (h, NULL, nmc_fields_dev_status); - complete_field (h, NULL, nmc_fields_dev_show_general); - complete_field (h, NULL, nmc_fields_dev_show_connections); - complete_field (h, NULL, nmc_fields_dev_show_cap); - complete_field (h, NULL, nmc_fields_dev_show_wired_prop); - complete_field (h, NULL, nmc_fields_dev_show_wifi_prop); - complete_field (h, NULL, nmc_fields_dev_show_wimax_prop); - complete_field (h, NULL, nmc_fields_dev_wifi_list); - complete_field (h, NULL, nmc_fields_dev_wimax_list); - complete_field (h, NULL, nmc_fields_dev_show_master_prop); - complete_field (h, NULL, nmc_fields_dev_show_team_prop); - complete_field (h, NULL, nmc_fields_dev_show_vlan_prop); - complete_field (h, NULL, nmc_fields_dev_show_bluetooth); - complete_field (h, NULL, nmc_fields_dev_show_sections); - complete_field (h, NULL, nmc_fields_dev_lldp_list); - - complete_field (h, "connection", nmc_fields_setting_connection); - complete_field (h, "802-3-ethernet", nmc_fields_setting_wired); - complete_field (h, "802-1x", nmc_fields_setting_8021X); - complete_field (h, "802-11-wireless", nmc_fields_setting_wireless); - complete_field (h, "802-11-wireless-security", nmc_fields_setting_wireless_security); - complete_field (h, "ipv4", nmc_fields_setting_ip4_config); - complete_field (h, "ipv6", nmc_fields_setting_ip6_config); - complete_field (h, "serial", nmc_fields_setting_serial); - complete_field (h, "ppp", nmc_fields_setting_ppp); - complete_field (h, "pppoe", nmc_fields_setting_pppoe); - complete_field (h, "adsl", nmc_fields_setting_adsl); - complete_field (h, "gsm", nmc_fields_setting_gsm); - complete_field (h, "cdma", nmc_fields_setting_cdma); - complete_field (h, "bluetooth", nmc_fields_setting_bluetooth); - complete_field (h, "802-11-olpc-mesh", nmc_fields_setting_olpc_mesh); - complete_field (h, "vpn", nmc_fields_setting_vpn); - complete_field (h, "wimax", nmc_fields_setting_wimax); - complete_field (h, "infiniband", nmc_fields_setting_infiniband); - complete_field (h, "bond", nmc_fields_setting_bond); - complete_field (h, "vlan", nmc_fields_setting_vlan); - complete_field (h, "bridge", nmc_fields_setting_bridge); - complete_field (h, "bridge-port", nmc_fields_setting_bridge_port); - complete_field (h, "team", nmc_fields_setting_team); - complete_field (h, "team-port", nmc_fields_setting_team_port); - complete_field (h, "dcb", nmc_fields_setting_dcb); - complete_field (h, "tun", nmc_fields_setting_tun); - complete_field (h, "ip-tunnel", nmc_fields_setting_ip_tunnel); - complete_field (h, "macvlan", nmc_fields_setting_macvlan); - complete_field (h, "vxlan", nmc_fields_setting_vxlan); - - g_hash_table_foreach (h, complete_one, (gpointer) prefix); + const char *option_with_value[2] = { option, prefix }; + + h = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL); + + complete_field (h, metagen_ip4_config); + complete_field (h, nmc_fields_dhcp4_config); + complete_field (h, nmc_fields_ip6_config); + complete_field (h, nmc_fields_dhcp6_config); + complete_field (h, nmc_fields_con_show); + complete_field (h, nmc_fields_con_active_details_general); + complete_field (h, nmc_fields_con_active_details_vpn); + complete_field (h, nmc_fields_con_active_details_groups); + complete_field (h, nmc_fields_dev_status); + complete_field (h, nmc_fields_dev_show_general); + complete_field (h, nmc_fields_dev_show_connections); + complete_field (h, nmc_fields_dev_show_cap); + complete_field (h, nmc_fields_dev_show_wired_prop); + complete_field (h, nmc_fields_dev_show_wifi_prop); + complete_field (h, nmc_fields_dev_show_wimax_prop); + complete_field (h, nmc_fields_dev_wifi_list); + complete_field (h, nmc_fields_dev_wimax_list); + complete_field (h, nmc_fields_dev_show_master_prop); + complete_field (h, nmc_fields_dev_show_team_prop); + complete_field (h, nmc_fields_dev_show_vlan_prop); + complete_field (h, nmc_fields_dev_show_bluetooth); + complete_field (h, nmc_fields_dev_show_sections); + complete_field (h, nmc_fields_dev_lldp_list); + + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) + complete_field_setting (h, i); + + g_hash_table_foreach (h, complete_one, (gpointer) &option_with_value[0]); g_hash_table_destroy (h); } +static void +complete_option_with_value (const char *option, const char *prefix, ...) +{ + va_list args; + const char *candidate; + + va_start (args, prefix); + while ((candidate = va_arg (args, const char *))) { + if (!*prefix || matches (prefix, candidate)) { + if (option != prefix) { + /* value prefix was not a standalone argument, + * it was part of --option=<value> argument. + * Repeat the part leading to "=". */ + g_print ("%s=", option); + } + g_print ("%s\n", candidate); + } + } + va_end (args); +} static void usage (void) @@ -207,6 +222,57 @@ static const NMCCommand nmcli_cmds[] = { }; static gboolean +matches_arg (NmCli *nmc, int *argc, char ***argv, const char *pattern, char **arg) +{ + char *opt = *argv[0]; + + if (nmc->return_value != NMC_RESULT_SUCCESS) { + /* Don't process further matches if there has been an error. */ + return FALSE; + } + + if (opt[1] == '-') { + /* We know one '-' was already seen by the caller. + * Skip it if there's a second one*/ + opt++; + } + + if (arg) { + /* If there's a "=" separator, replace it with NUL so that matches() + * works and consider the part after it to be the arguemnt's value. */ + *arg = strchr (opt, '='); + if (*arg) { + **arg = '\0'; + (*arg)++; + } + } + + if (!matches (opt, pattern)) { + if (arg && *arg) { + /* Back off the replacement of "=". */ + (*arg)--; + **arg = '='; + } + return FALSE; + } + + if (arg && !*arg) { + /* We need a value, but the option didn't contain a "=<value>" part. + * Proceed to the next argument. */ + (*argc)--; + (*argv)++; + if (!*argc) { + g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return FALSE; + } + *arg = *argv[0]; + } + + return TRUE; +} + +static gboolean process_command_line (NmCli *nmc, int argc, char **argv) { char *base; @@ -225,171 +291,129 @@ process_command_line (NmCli *nmc, int argc, char **argv) /* parse options */ while (argc) { - char *opt = argv[0]; - if (opt[0] != '-') + char *value; + + if (argv[0][0] != '-') break; if (argc == 1 && nmc->complete) { - nmc_complete_strings (opt, "--terse", "--pretty", "--mode", "--colors", "--escape", + nmc_complete_strings (argv[0], "--terse", "--pretty", "--mode", "--colors", "--escape", "--fields", "--nocheck", "--get-values", "--wait", "--version", "--help", NULL); } - if (opt[1] == '-') { - opt++; + if (argv[0][1] == '-' && argv[0][2] == '\0') { /* '--' ends options */ - if (opt[1] == '\0') { - next_arg (nmc, &argc, &argv, NULL); - break; - } + next_arg (nmc, &argc, &argv, NULL); + break; } - if (matches (opt, "-terse")) { - if (nmc->print_output == NMC_PRINT_TERSE) { + if (matches_arg (nmc, &argc, &argv, "-terse", NULL)) { + if (nmc->nmc_config.print_output == NMC_PRINT_TERSE) { g_string_printf (nmc->return_text, _("Error: Option '--terse' is specified the second time.")); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; return FALSE; } - else if (nmc->print_output == NMC_PRINT_PRETTY) { + else if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) { g_string_printf (nmc->return_text, _("Error: Option '--terse' is mutually exclusive with '--pretty'.")); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; return FALSE; } else - nmc->print_output = NMC_PRINT_TERSE; - } else if (matches (opt, "-pretty")) { - if (nmc->print_output == NMC_PRINT_PRETTY) { + nmc->nmc_config_mutable.print_output = NMC_PRINT_TERSE; + } else if (matches_arg (nmc, &argc, &argv, "-pretty", NULL)) { + if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) { g_string_printf (nmc->return_text, _("Error: Option '--pretty' is specified the second time.")); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; return FALSE; } - else if (nmc->print_output == NMC_PRINT_TERSE) { + else if (nmc->nmc_config.print_output == NMC_PRINT_TERSE) { g_string_printf (nmc->return_text, _("Error: Option '--pretty' is mutually exclusive with '--terse'.")); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; return FALSE; } else - nmc->print_output = NMC_PRINT_PRETTY; - } else if (matches (opt, "-mode")) { + nmc->nmc_config_mutable.print_output = NMC_PRINT_PRETTY; + } else if (matches_arg (nmc, &argc, &argv, "-mode", &value)) { nmc->mode_specified = TRUE; - argc--; - argv++; - if (!argc) { - g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return FALSE; - } if (argc == 1 && nmc->complete) - nmc_complete_strings (argv[0], "tabular", "multiline", NULL); - if (matches (argv[0], "tabular")) - nmc->multiline_output = FALSE; - else if (matches (argv[0], "multiline")) - nmc->multiline_output = TRUE; + complete_option_with_value (argv[0], value, "tabular", "multiline", NULL); + if (matches (value, "tabular")) + nmc->nmc_config_mutable.multiline_output = FALSE; + else if (matches (value, "multiline")) + nmc->nmc_config_mutable.multiline_output = TRUE; else { - g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[0], opt); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return FALSE; - } - } else if (matches (opt, "-colors")) { - argc--; - argv++; - if (!argc) { - g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt); + g_string_printf (nmc->return_text, _("Error: '%s' is not a valid argument for '%s' option."), value, argv[0]); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; return FALSE; } + } else if (matches_arg (nmc, &argc, &argv, "-colors", &value)) { if (argc == 1 && nmc->complete) - nmc_complete_strings (argv[0], "yes", "no", "auto", NULL); - if (matches (argv[0], "auto")) - nmc->use_colors = NMC_USE_COLOR_AUTO; - else if (matches (argv[0], "yes")) - nmc->use_colors = NMC_USE_COLOR_YES; - else if (matches (argv[0], "no")) - nmc->use_colors = NMC_USE_COLOR_NO; + complete_option_with_value (argv[0], value, "yes", "no", "auto", NULL); + if (matches (value, "auto")) + nmc->nmc_config_mutable.use_colors = NMC_USE_COLOR_AUTO; + else if (matches (value, "yes")) + nmc->nmc_config_mutable.use_colors = NMC_USE_COLOR_YES; + else if (matches (value, "no")) + nmc->nmc_config_mutable.use_colors = NMC_USE_COLOR_NO; else { - g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[0], opt); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return FALSE; - } - } else if (matches (opt, "-escape")) { - argc--; - argv++; - if (!argc) { - g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt); + g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), value, argv[0]); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; return FALSE; } + } else if (matches_arg (nmc, &argc, &argv, "-escape", &value)) { if (argc == 1 && nmc->complete) - nmc_complete_strings (argv[0], "yes", "no", NULL); - if (matches (argv[0], "yes")) - nmc->escape_values = TRUE; - else if (matches (argv[0], "no")) - nmc->escape_values = FALSE; + complete_option_with_value (argv[0], value, "yes", "no", NULL); + if (matches (value, "yes")) + nmc->nmc_config_mutable.escape_values = TRUE; + else if (matches (value, "no")) + nmc->nmc_config_mutable.escape_values = FALSE; else { - g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[0], opt); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return FALSE; - } - } else if (matches (opt, "-fields")) { - argc--; - argv++; - if (!argc) { - g_string_printf (nmc->return_text, _("Error: fields for '%s' options are missing."), opt); + g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), value, argv[0]); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; return FALSE; } + } else if (matches_arg (nmc, &argc, &argv, "-fields", &value)) { if (argc == 1 && nmc->complete) - complete_fields (argv[0]); - nmc->required_fields = g_strdup (argv[0]); - } else if (matches (opt, "-get-values")) { - argc--; - argv++; - if (!argc) { - g_string_printf (nmc->return_text, _("Error: fields for '%s' options are missing."), opt); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return FALSE; - } + complete_fields (argv[0], value); + nmc->required_fields = g_strdup (value); + } else if (matches_arg (nmc, &argc, &argv, "-get-values", &value)) { if (argc == 1 && nmc->complete) - complete_fields (argv[0]); - nmc->required_fields = g_strdup (argv[0]); - nmc->print_output = NMC_PRINT_TERSE; + complete_fields (argv[0], value); + nmc->required_fields = g_strdup (value); + nmc->nmc_config_mutable.print_output = NMC_PRINT_TERSE; /* We want fixed tabular mode here, but just set the mode specified and rely on the initialization * in nmc_init: in this way we allow use of "-m multiline" to swap the output mode also if placed * before the "-g <field>" option (-g may be still more practical and easy to remember than -t -f). */ nmc->mode_specified = TRUE; - } else if (matches (opt, "-nocheck")) { + } else if (matches_arg (nmc, &argc, &argv, "-nocheck", NULL)) { /* ignore for backward compatibility */ - } else if (matches (opt, "-wait")) { + } else if (matches_arg (nmc, &argc, &argv, "-wait", &value)) { unsigned long timeout; - argc--; - argv++; - if (!argc) { - g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return FALSE; - } - if (!nmc_string_to_uint (argv[0], TRUE, 0, G_MAXINT, &timeout)) { - g_string_printf (nmc->return_text, _("Error: '%s' is not a valid timeout for '%s' option."), - argv[0], opt); + if (!nmc_string_to_uint (value, TRUE, 0, G_MAXINT, &timeout)) { + g_string_printf (nmc->return_text, _("Error: '%s' is not a valid timeout."), value); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; return FALSE; } nmc->timeout = (int) timeout; - } else if (matches (opt, "-version")) { + } else if (matches_arg (nmc, &argc, &argv, "-version", NULL)) { if (!nmc->complete) g_print (_("nmcli tool, version %s\n"), NMCLI_VERSION); return NMC_RESULT_SUCCESS; - } else if (matches (opt, "-help")) { + } else if (matches_arg (nmc, &argc, &argv, "-help", NULL)) { if (!nmc->complete) usage (); return NMC_RESULT_SUCCESS; } else { - g_string_printf (nmc->return_text, _("Error: Option '%s' is unknown, try 'nmcli -help'."), opt); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + if (nmc->return_value == NMC_RESULT_SUCCESS) { + g_string_printf (nmc->return_text, _("Error: Option '%s' is unknown, try 'nmcli -help'."), argv[0]); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + } return FALSE; } + next_arg (nmc, &argc, &argv, NULL); } @@ -545,28 +569,27 @@ nmc_init (NmCli *nmc) nmc->should_wait = 0; nmc->nowait_flag = TRUE; - nmc->print_output = NMC_PRINT_NORMAL; - nmc->multiline_output = FALSE; + nmc->nmc_config_mutable.print_output = NMC_PRINT_NORMAL; + nmc->nmc_config_mutable.multiline_output = FALSE; nmc->mode_specified = FALSE; - nmc->escape_values = TRUE; + nmc->nmc_config_mutable.escape_values = TRUE; nmc->required_fields = NULL; - nmc->output_data = g_ptr_array_new_full (20, g_free); - memset (&nmc->print_fields, '\0', sizeof (NmcPrintFields)); nmc->ask = FALSE; nmc->complete = FALSE; - nmc->show_secrets = FALSE; - nmc->use_colors = NMC_USE_COLOR_AUTO; - nmc->in_editor = FALSE; + nmc->nmc_config_mutable.show_secrets = FALSE; + nmc->nmc_config_mutable.use_colors = NMC_USE_COLOR_AUTO; + nmc->nmc_config_mutable.in_editor = FALSE; nmc->editor_status_line = FALSE; nmc->editor_save_confirmation = TRUE; - nmc->editor_show_secrets = FALSE; - nmc->editor_prompt_color = NMC_TERM_COLOR_NORMAL; + nmc->editor_prompt_color = NM_META_TERM_COLOR_NORMAL; } static void nmc_cleanup (NmCli *nmc) { - if (nmc->client) g_object_unref (nmc->client); + pid_t ret; + + g_clear_object (&nmc->client); g_string_free (nmc->return_text, TRUE); @@ -579,8 +602,15 @@ nmc_cleanup (NmCli *nmc) g_hash_table_destroy (nmc->pwds_hash); g_free (nmc->required_fields); - nmc_empty_output_fields (nmc); - g_ptr_array_unref (nmc->output_data); + + if (nmc->pager_pid > 0) { + fclose (stdout); + fclose (stderr); + do { + ret = waitpid (nmc->pager_pid, NULL, 0); + } while (ret == -1 && errno == EINTR); + nmc->pager_pid = 0; + } nmc_polkit_agent_fini (nmc); } |