summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancesco Giudici <fgiudici@redhat.com>2016-06-21 16:30:07 +0200
committerFrancesco Giudici <fgiudici@redhat.com>2016-06-21 16:30:07 +0200
commit68d48fa50769c34cf8f10b90788f5dca3ea60191 (patch)
treeb65780fecbe62b7a11115a8254de3b841e34da9d
parent072358dad08b4b2206f15e6b0ebf9f096e81c05e (diff)
parent00b362bcf2052671788ce03d6cafb253904e991b (diff)
downloadNetworkManager-68d48fa50769c34cf8f10b90788f5dca3ea60191.tar.gz
nmlci merge branch 'fg/autocomplete_fix_rh1301226_with_LR_patches'
https://bugzilla.gnome.org/show_bug.cgi?id=724860 https://bugzilla.redhat.com/show_bug.cgi?id=1301226
-rw-r--r--clients/cli/connections.c416
-rw-r--r--clients/cli/nmcli-completion41
-rw-r--r--clients/cli/nmcli.c14
-rw-r--r--clients/cli/nmcli.h1
4 files changed, 331 insertions, 141 deletions
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index 506bfe0fd0..c10db7b446 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -1590,6 +1590,10 @@ do_connections_show (NmCli *nmc, gboolean active_only, gboolean show_secrets,
char *profile_flds = NULL, *active_flds = NULL;
GPtrArray *invisibles, *sorted_cons;
+ /* Not (yet?) supported */
+ if (nmc->complete)
+ goto finish;
+
if (argc == 0) {
char *fields_str;
char *fields_all = NMC_FIELDS_CON_SHOW_ALL;
@@ -2358,6 +2362,9 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
const char *name = NULL;
char *line = NULL;
+ /* Not (yet?) supported */
+ if (nmc->complete)
+ return nmc->return_value;
/*
* Set default timeout for connection activation.
* Activation can take quite a long time, use 90 seconds.
@@ -2547,6 +2554,10 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
int arg_num = argc;
int idx = 0;
+ /* Not (yet?) supported */
+ if (nmc->complete)
+ return nmc->return_value;
+
if (nmc->timeout == -1)
nmc->timeout = 10;
@@ -2900,6 +2911,98 @@ get_valid_settings_array (const char *con_type)
return NULL;
}
+/* get_valid_properties_string:
+ * @array: base properties for the current connection type
+ * @array_slv: slave properties (or ipv4/ipv6 ones) for the current connection type
+ * @modifier: to prepend to each element of the returned list
+ * @prefix: only properties matching the prefix will be returned
+ * @postfix: required prefix on the property args; if a empty string is passed, is
+ * assumed that the @prefix is a shortcut, so it should not be completed
+ * but left as is (and an additional check for shortcut ambiguity is performed)
+ *
+ * Returns a list of properties compatible with the current connection type
+ * for the shell autocompletion functionality.
+ *
+ * Returns: list of property.arg elements
+ */
+static char *
+get_valid_properties_string (const NameItem *array,
+ const NameItem *array_slv,
+ char modifier,
+ const char *prefix,
+ const char *postfix)
+{
+ const NameItem *iter = array;
+ const NmcOutputField *field_iter;
+ const char *prop_name = NULL;
+ GString *str;
+ int i, j;
+
+ g_return_val_if_fail (prefix, NULL);
+
+ str = g_string_sized_new (1024);
+
+ for (i = 0; i < 2; i++, iter = array_slv) {
+ while (iter && iter->name) {
+ if ( !(g_str_has_prefix (iter->name, prefix))
+ && (!(iter->alias) || !g_str_has_prefix (iter->alias, prefix))) {
+ iter++;
+ continue;
+ }
+ /* If postix (so prefix is terminated by a dot), check
+ * that prefix is not ambiguous */
+ if (postfix) {
+ if (prop_name)
+ return g_string_free (str, TRUE);
+ prop_name = prefix;
+ } else {
+ prop_name = iter->name;
+ }
+
+ /* Search the array with the arguments of the current property */
+ j = 0;
+ while (!nm_streq0 (iter->name, nmc_fields_settings_names[j].name)) {
+ g_assert (nmc_fields_settings_names[j].name);
+ j++;
+ }
+ field_iter = nmc_fields_settings_names[j].group;
+
+ j = 0;
+ while (field_iter[j].name) {
+ gchar *new;
+ const char *arg_name = field_iter[j].name;
+
+ /* If required, expand the alias too */
+ if (!postfix && iter->alias) {
+ if (modifier)
+ g_string_append_c (str, modifier);
+ new = g_strdup_printf ("%s.%s\n",
+ iter->alias,
+ arg_name);
+ g_string_append (str, new);
+ g_free (new);
+ }
+
+ if (postfix && !g_str_has_prefix (arg_name, postfix)) {
+ j++;
+ continue;
+ }
+
+ if (modifier)
+ g_string_append_c (str, modifier);
+ new = g_strdup_printf ("%s.%s\n",
+ prop_name,
+ arg_name);
+ g_string_append (str, new);
+ g_free (new);
+ j++;
+ }
+ iter++;
+ }
+ }
+ return g_string_free (str, FALSE);
+}
+
/*
* Check if 'val' is valid string in either array->name or array->alias for
* both array parameters (array & array_slv).
@@ -4601,8 +4704,36 @@ do_questionnaire_ip_tunnel (char **local, char **parent)
}
}
+static void
+complete_property_name (NmCli *nmc, NMConnection *connection,
+ char modifier,
+ const gchar *prefix,
+ const gchar *postfix)
+{
+ NMSettingConnection *s_con;
+ const NameItem *valid_settings_main = NULL;
+ const NameItem *valid_settings_slave = NULL;
+ const char *connection_type = NULL;
+ const char *slave_type = NULL;
+ gs_free char *slv_type = NULL;
+ gs_free char *word_list = NULL;
+
+ connection_type = nm_connection_get_connection_type (connection);
+ s_con = nm_connection_get_setting_connection (connection);
+ if (s_con)
+ slave_type = nm_setting_connection_get_slave_type (s_con);
+ slv_type = g_strdup_printf ("%s-slave", slave_type ? slave_type : "no");
+ valid_settings_main = get_valid_settings_array (connection_type);
+ valid_settings_slave = get_valid_settings_array (slv_type);
+
+ word_list = get_valid_properties_string (valid_settings_main, valid_settings_slave, modifier, prefix, postfix);
+ if (word_list)
+ g_print ("%s", word_list);
+}
+
static gboolean
-read_connection_properties (NMConnection *connection,
+read_connection_properties (NmCli *nmc,
+ NMConnection *connection,
int argc,
char **argv,
GError **error)
@@ -4610,13 +4741,12 @@ read_connection_properties (NMConnection *connection,
NMSetting *setting;
NMSettingConnection *s_con;
const char *con_type;
- const char *s_dot_p;
+ const char *s_dot_p = NULL;
const char *value;
char **strv = NULL;
char *slv_type = NULL;
const char *setting_name;
- gboolean append = FALSE;
- gboolean remove = FALSE;
+ char modifier = '\0';
gboolean success = FALSE;
GError *local = NULL;
@@ -4644,29 +4774,20 @@ read_connection_properties (NMConnection *connection,
next_arg (&argc, &argv);
if (!s_dot_p) {
+ /* XXX: can not happen? */
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
_("Error: <setting>.<property> argument is missing."));
goto finish;
}
- if (!value) {
- g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
- _("Error: value for '%s' is missing."), s_dot_p);
- goto finish;
- }
- /* Empty string will reset the value to default */
- if (value[0] == '\0')
- value = NULL;
-
- if (s_dot_p[0] == '+') {
- s_dot_p++;
- append = TRUE;
- } else if (s_dot_p[0] == '-') {
- s_dot_p++;
- remove = TRUE;
- }
+ if (s_dot_p[0] == '+' || s_dot_p[0] == '-')
+ modifier = *s_dot_p++;
strv = g_strsplit (s_dot_p, ".", 2);
if (g_strv_length (strv) != 2) {
+ if (nmc->complete) {
+ complete_property_name (nmc, connection, modifier, s_dot_p, NULL);
+ break;
+ }
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
_("Error: invalid <setting>.<property> '%s'."), s_dot_p);
goto finish;
@@ -4703,9 +4824,18 @@ read_connection_properties (NMConnection *connection,
goto finish;
}
- if (!remove) {
+ if (!value) {
+ g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: value for '%s' is missing."), s_dot_p);
+ goto finish;
+ }
+ /* Empty string will reset the value to default */
+ if (value[0] == '\0')
+ value = NULL;
+
+ if (modifier != '-') {
/* Set/add value */
- if (!append)
+ if (modifier != '+')
nmc_setting_reset_property (setting, property_name, NULL);
if (!nmc_setting_set_property (setting, property_name, value, &local)) {
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -4743,6 +4873,10 @@ read_connection_properties (NMConnection *connection,
success = TRUE;
finish:
+ if (!success && nmc->complete) {
+ complete_property_name (nmc, connection, modifier, strv[0], strv[1]);
+ success = TRUE;
+ }
if (strv)
g_strfreev (strv);
g_free (slv_type);
@@ -4801,11 +4935,9 @@ complete_slave (NMSettingConnection *s_con,
}
static gboolean
-complete_connection_by_type (NMConnection *connection,
+complete_connection_by_type (NmCli *nmc,
+ NMConnection *connection,
const char *con_type,
- const GPtrArray *all_connections,
- gboolean ask,
- gboolean show_secrets,
int argc,
char **argv,
GError **error)
@@ -4861,7 +4993,7 @@ complete_connection_by_type (NMConnection *connection,
mtu = g_strdup (mtu_c);
mac = g_strdup (mac_c);
cloned_mac = g_strdup (cloned_mac_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_ethernet (TRUE, &mtu, &mac, &cloned_mac);
if (!check_and_convert_mtu (mtu, &mtu_int, error))
@@ -4921,7 +5053,7 @@ cleanup_wired:
mode = g_strdup (mode_c);
parent = g_strdup (parent_c);
p_key = g_strdup (p_key_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_infiniband (&mtu, &mac, &mode, &parent, &p_key);
if (!check_and_convert_mtu (mtu, &mtu_int, error))
@@ -4981,7 +5113,7 @@ cleanup_ib:
char *cloned_mac = NULL;
const char *mode_c = NULL;
char *mode = NULL;
- nmc_arg_t exp_args[] = { {"ssid", TRUE, &ssid, !ask},
+ nmc_arg_t exp_args[] = { {"ssid", TRUE, &ssid, !nmc->ask},
{"mtu", TRUE, &mtu_c, FALSE},
{"mac", TRUE, &mac_c, FALSE},
{"cloned-mac", TRUE, &cloned_mac_c, FALSE},
@@ -4991,7 +5123,7 @@ cleanup_ib:
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!ssid && ask)
+ if (!ssid && nmc->ask)
ssid = ssid_ask = nmc_readline (_("SSID: "));
if (!ssid) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -5004,7 +5136,7 @@ cleanup_ib:
mac = g_strdup (mac_c);
cloned_mac = g_strdup (cloned_mac_c);
mode = g_strdup (mode_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_wifi (&mtu, &mac, &cloned_mac, &mode);
if (!check_and_convert_mtu (mtu, &mtu_int, error))
@@ -5051,14 +5183,14 @@ cleanup_wifi:
char *nsp_name_ask = NULL;
const char *mac_c = NULL;
char *mac = NULL;
- nmc_arg_t exp_args[] = { {"nsp", TRUE, &nsp_name, !ask},
+ nmc_arg_t exp_args[] = { {"nsp", TRUE, &nsp_name, !nmc->ask},
{"mac", TRUE, &mac_c, FALSE},
{NULL} };
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!nsp_name && ask)
+ if (!nsp_name && nmc->ask)
nsp_name = nsp_name_ask = nmc_readline (_("WiMAX NSP name: "));
if (!nsp_name) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -5068,7 +5200,7 @@ cleanup_wifi:
/* Also ask for all optional arguments if '--ask' is specified. */
mac = g_strdup (mac_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_wimax (&mac);
if (!check_mac (mac, ARPHRD_ETHER, "mac", error))
@@ -5103,7 +5235,7 @@ cleanup_wimax:
guint32 mtu_int = 0;
const char *mac_c = NULL;
char *mac = NULL;
- nmc_arg_t exp_args[] = { {"username", TRUE, &username, !ask},
+ nmc_arg_t exp_args[] = { {"username", TRUE, &username, !nmc->ask},
{"password", TRUE, &password_c, FALSE},
{"service", TRUE, &service_c, FALSE},
{"mtu", TRUE, &mtu_c, FALSE},
@@ -5113,7 +5245,7 @@ cleanup_wimax:
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!username && ask)
+ if (!username && nmc->ask)
username = username_ask = nmc_readline (_("PPPoE username: "));
if (!username) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -5126,8 +5258,8 @@ cleanup_wimax:
service = g_strdup (service_c);
mtu = g_strdup (mtu_c);
mac = g_strdup (mac_c);
- if (ask)
- do_questionnaire_pppoe (show_secrets, &password, &service, &mtu, &mac);
+ if (nmc->ask)
+ do_questionnaire_pppoe (nmc->show_secrets, &password, &service, &mtu, &mac);
if (!check_and_convert_mtu (mtu, &mtu_int, error))
goto cleanup_pppoe;
@@ -5177,7 +5309,7 @@ cleanup_pppoe:
is_gsm = !strcmp (con_type, NM_SETTING_GSM_SETTING_NAME);
if (is_gsm)
- gsm_args[i++] = (nmc_arg_t) {"apn", TRUE, &apn, !ask};
+ gsm_args[i++] = (nmc_arg_t) {"apn", TRUE, &apn, !nmc->ask};
gsm_args[i++] = (nmc_arg_t) {"user", TRUE, &user_c, FALSE};
gsm_args[i++] = (nmc_arg_t) {"password", TRUE, &password_c, FALSE};
gsm_args[i++] = (nmc_arg_t) {NULL};
@@ -5185,7 +5317,7 @@ cleanup_pppoe:
if (!nmc_parse_args (gsm_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!apn && ask && is_gsm)
+ if (!apn && nmc->ask && is_gsm)
apn = apn_ask = nmc_readline (_("APN: "));
if (!apn && is_gsm) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -5196,8 +5328,8 @@ cleanup_pppoe:
/* Also ask for all optional arguments if '--ask' is specified. */
user = g_strdup (user_c);
password = g_strdup (password_c);
- if (ask)
- do_questionnaire_mobile (show_secrets, &user, &password);
+ if (nmc->ask)
+ do_questionnaire_mobile (nmc->show_secrets, &user, &password);
if (is_gsm) {
g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_GSM_SETTING_NAME, NULL);
@@ -5239,14 +5371,14 @@ cleanup_mobile:
char *addr_ask = NULL;
const char *bt_type_c = NULL;
char *bt_type = NULL;
- nmc_arg_t exp_args[] = { {"addr", TRUE, &addr, !ask},
+ nmc_arg_t exp_args[] = { {"addr", TRUE, &addr, !nmc->ask},
{"bt-type", TRUE, &bt_type_c, FALSE},
{NULL} };
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!addr && ask)
+ if (!addr && nmc->ask)
addr = addr_ask = nmc_readline (_("Bluetooth device address: "));
if (!addr) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -5258,7 +5390,7 @@ cleanup_mobile:
/* Also ask for all optional arguments if '--ask' is specified. */
bt_type = g_strdup (bt_type_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_bluetooth (&bt_type);
/* Default to 'panu' if bt-type is not provided. */
@@ -5323,8 +5455,8 @@ cleanup_bt:
char *mtu = NULL;
guint32 mtu_int;
gboolean valid_mac = FALSE;
- nmc_arg_t exp_args[] = { {"dev", TRUE, &parent, !ask},
- {"id", TRUE, &vlan_id, !ask},
+ nmc_arg_t exp_args[] = { {"dev", TRUE, &parent, !nmc->ask},
+ {"id", TRUE, &vlan_id, !nmc->ask},
{"flags", TRUE, &flags_c, FALSE},
{"ingress", TRUE, &ingress_c, FALSE},
{"egress", TRUE, &egress_c, FALSE},
@@ -5334,14 +5466,14 @@ cleanup_bt:
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!parent && ask)
+ if (!parent && nmc->ask)
parent = parent_ask = nmc_readline (_("VLAN parent device or connection UUID: "));
if (!parent) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
_("Error: 'dev' is required."));
return FALSE;
}
- if (!vlan_id && ask)
+ if (!vlan_id && nmc->ask)
vlan_id = vlan_id_ask = nmc_readline (_("VLAN ID <0-4094>: "));
if (!vlan_id) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -5371,7 +5503,7 @@ cleanup_bt:
flags = g_strdup (flags_c);
ingress = g_strdup (ingress_c);
egress = g_strdup (egress_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_vlan (&mtu, &flags, &ingress, &egress);
if (!check_and_convert_mtu (mtu, &mtu_int, error))
@@ -5466,7 +5598,7 @@ cleanup_vlan:
bond_arpinterval = g_strdup (bond_arpinterval_c);
bond_arpiptarget = g_strdup (bond_arpiptarget_c);
bond_lacp_rate = g_strdup (bond_lacp_rate_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_bond (&bond_mode, &bond_primary, &bond_miimon,
&bond_downdelay, &bond_updelay,
&bond_arpinterval, &bond_arpiptarget,
@@ -5475,7 +5607,7 @@ cleanup_vlan:
/* Generate ifname if connection doesn't have one */
ifname = nm_setting_connection_get_interface_name (s_con);
if (!ifname) {
- char *bond_ifname = unique_master_iface_ifname (all_connections, "nm-bond");
+ char *bond_ifname = unique_master_iface_ifname (nmc->connections, "nm-bond");
g_object_set (s_con,
NM_SETTING_CONNECTION_INTERFACE_NAME, bond_ifname,
@@ -5548,7 +5680,7 @@ cleanup_bond:
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!complete_slave (s_con, all_connections, NM_SETTING_BOND_SETTING_NAME, master, type, ask, error))
+ if (!complete_slave (s_con, nmc->connections, NM_SETTING_BOND_SETTING_NAME, master, type, nmc->ask, error))
return FALSE;
/* Change properties in 'connection' setting */
@@ -5573,13 +5705,13 @@ cleanup_bond:
/* Also ask for all optional arguments if '--ask' is specified. */
config = g_strdup (config_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_team (&config);
/* Generate ifname if conneciton doesn't have one */
ifname = nm_setting_connection_get_interface_name (s_con);
if (!ifname) {
- char *team_ifname = unique_master_iface_ifname (all_connections, "nm-team");
+ char *team_ifname = unique_master_iface_ifname (nmc->connections, "nm-team");
g_object_set (s_con,
NM_SETTING_CONNECTION_INTERFACE_NAME, team_ifname,
@@ -5626,12 +5758,12 @@ cleanup_team:
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!complete_slave (s_con, all_connections, NM_SETTING_TEAM_SETTING_NAME, master, type, ask, error))
+ if (!complete_slave (s_con, nmc->connections, NM_SETTING_TEAM_SETTING_NAME, master, type, nmc->ask, error))
return FALSE;
/* Also ask for all optional arguments if '--ask' is specified. */
config = g_strdup (config_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_team_slave (&config);
/* Add 'team-port' setting */
@@ -5706,14 +5838,14 @@ cleanup_team_slave:
ageing_time = g_strdup (ageing_time_c);
mcast_snoop = g_strdup (mcast_snoop_c);
mac = g_strdup (mac_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_bridge (&stp, &priority, &fwd_delay, &hello_time,
&max_age, &ageing_time, &mcast_snoop, &mac);
/* Generate ifname if conneciton doesn't have one */
ifname = nm_setting_connection_get_interface_name (s_con);
if (!ifname) {
- char *bridge_ifname = unique_master_iface_ifname (all_connections, "nm-bridge");
+ char *bridge_ifname = unique_master_iface_ifname (nmc->connections, "nm-bridge");
g_object_set (s_con,
NM_SETTING_CONNECTION_INTERFACE_NAME, bridge_ifname,
@@ -5826,7 +5958,7 @@ cleanup_bridge:
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!complete_slave (s_con, all_connections, NM_SETTING_BRIDGE_SETTING_NAME, master, type, ask, error))
+ if (!complete_slave (s_con, nmc->connections, NM_SETTING_BRIDGE_SETTING_NAME, master, type, nmc->ask, error))
return FALSE;
/* Add 'bridge-port' setting */
@@ -5838,7 +5970,7 @@ cleanup_bridge:
priority = g_strdup (priority_c);
path_cost = g_strdup (path_cost_c);
hairpin = g_strdup (hairpin_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_bridge_slave (&priority, &path_cost, &hairpin);
if (priority)
@@ -5890,14 +6022,14 @@ cleanup_bridge_slave:
const char *user_c = NULL;
char *user = NULL;
gs_free char *service_type_free = NULL;
- nmc_arg_t exp_args[] = { {"vpn-type", TRUE, &vpn_type, !ask},
+ nmc_arg_t exp_args[] = { {"vpn-type", TRUE, &vpn_type, !nmc->ask},
{"user", TRUE, &user_c, FALSE},
{NULL} };
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!vpn_type && ask)
+ if (!vpn_type && nmc->ask)
vpn_type = vpn_type_ask = nmc_readline (PROMPT_VPN_TYPE);
if (!vpn_type) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -5915,7 +6047,7 @@ cleanup_bridge_slave:
/* Also ask for all optional arguments if '--ask' is specified. */
user = g_strdup (user_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_vpn (&user);
/* Add 'vpn' setting */
@@ -5942,7 +6074,7 @@ cleanup_vpn:
unsigned long chan;
const char *dhcp_anycast_c = NULL;
char *dhcp_anycast = NULL;
- nmc_arg_t exp_args[] = { {"ssid", TRUE, &ssid, !ask},
+ nmc_arg_t exp_args[] = { {"ssid", TRUE, &ssid, !nmc->ask},
{"channel", TRUE, &channel_c, FALSE},
{"dhcp-anycast", TRUE, &dhcp_anycast_c, FALSE},
{NULL} };
@@ -5950,7 +6082,7 @@ cleanup_vpn:
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!ssid && ask)
+ if (!ssid && nmc->ask)
ssid = ssid_ask = nmc_readline (_("SSID: "));
if (!ssid) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -5961,7 +6093,7 @@ cleanup_vpn:
/* Also ask for all optional arguments if '--ask' is specified. */
channel = g_strdup (channel_c);
dhcp_anycast = g_strdup (dhcp_anycast_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_olpc (&channel, &dhcp_anycast);
if (channel) {
@@ -6008,8 +6140,8 @@ cleanup_olpc:
char *password = NULL;
const char *encapsulation_c = NULL;
char *encapsulation = NULL;
- nmc_arg_t exp_args[] = { {"username", TRUE, &username, !ask},
- {"protocol", TRUE, &protocol_c, !ask},
+ nmc_arg_t exp_args[] = { {"username", TRUE, &username, !nmc->ask},
+ {"protocol", TRUE, &protocol_c, !nmc->ask},
{"password", TRUE, &password_c, FALSE},
{"encapsulation", TRUE, &encapsulation_c, FALSE},
{NULL} };
@@ -6017,7 +6149,7 @@ cleanup_olpc:
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!username && ask)
+ if (!username && nmc->ask)
username = username_ask = nmc_readline (_("Username: "));
if (!username) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -6026,7 +6158,7 @@ cleanup_olpc:
}
#define PROMPT_ADSL_PROTO "(" NM_SETTING_ADSL_PROTOCOL_PPPOA "/" NM_SETTING_ADSL_PROTOCOL_PPPOE "/" NM_SETTING_ADSL_PROTOCOL_IPOATM "): "
- if (!protocol_c && ask)
+ if (!protocol_c && nmc->ask)
protocol_c = protocol_ask = nmc_readline (_("Protocol %s"), PROMPT_ADSL_PROTO);
if (!protocol_c) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -6040,8 +6172,8 @@ cleanup_olpc:
/* Also ask for all optional arguments if '--ask' is specified. */
password = g_strdup (password_c);
encapsulation = g_strdup (encapsulation_c);
- if (ask)
- do_questionnaire_adsl (show_secrets, &password, &encapsulation);
+ if (nmc->ask)
+ do_questionnaire_adsl (nmc->show_secrets, &password, &encapsulation);
if (!check_adsl_encapsulation (&encapsulation, error))
goto cleanup_adsl;
@@ -6080,15 +6212,15 @@ cleanup_adsl:
NMSettingMacvlanMode mode_enum;
gboolean valid_mac = FALSE;
gboolean tap_bool = FALSE;
- nmc_arg_t exp_args[] = { {"dev", TRUE, &parent, !ask},
- {"mode", TRUE, &mode, !ask},
+ nmc_arg_t exp_args[] = { {"dev", TRUE, &parent, !nmc->ask},
+ {"mode", TRUE, &mode, !nmc->ask},
{"tap", TRUE, &tap_c, FALSE},
{NULL} };
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!parent && ask)
+ if (!parent && nmc->ask)
parent = parent_ask = nmc_readline (_("MACVLAN parent device or connection UUID: "));
if (!parent) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -6105,7 +6237,7 @@ cleanup_adsl:
goto cleanup_macvlan;
}
- if (!mode && ask)
+ if (!mode && nmc->ask)
mode = mode_ask = nmc_readline (PROMPT_MACVLAN_MODE);
if (!mode) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -6121,7 +6253,7 @@ cleanup_adsl:
/* Also ask for all optional arguments if '--ask' is specified. */
tap = g_strdup (tap_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_macvlan (&tap);
if (tap) {
@@ -6171,7 +6303,7 @@ cleanup_macvlan:
const char *pi_c = NULL, *vnet_hdr_c = NULL, *multi_queue_c = NULL;
char *pi = NULL, *vnet_hdr = NULL, *multi_queue = NULL;
gboolean pi_bool, vnet_hdr_bool, multi_queue_bool;
- nmc_arg_t exp_args[] = { {"mode", TRUE, &mode_c, !ask},
+ nmc_arg_t exp_args[] = { {"mode", TRUE, &mode_c, !nmc->ask},
{"owner", TRUE, &owner_c, FALSE},
{"group", TRUE, &group_c, FALSE},
{"pi", TRUE, &pi_c, FALSE},
@@ -6182,7 +6314,7 @@ cleanup_macvlan:
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!mode_c && ask) {
+ if (!mode_c && nmc->ask) {
mode_ask = nmc_readline (_("Mode %s"), PROMPT_TUN_MODE);
mode_ask = mode_ask ? mode_ask : g_strdup ("tun");
mode_c = mode_ask;
@@ -6206,7 +6338,7 @@ cleanup_macvlan:
pi = g_strdup (pi_c);
vnet_hdr = g_strdup (vnet_hdr_c);
multi_queue = g_strdup (multi_queue_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_tun (&owner, &group, &pi, &vnet_hdr, &multi_queue);
if (pi) {
@@ -6278,16 +6410,16 @@ cleanup_tun:
char *parent = NULL;
gboolean success = FALSE;
NMIPTunnelMode mode_enum;
- nmc_arg_t exp_args[] = { {"mode", TRUE, &mode_c, !ask},
+ nmc_arg_t exp_args[] = { {"mode", TRUE, &mode_c, !nmc->ask},
{"local", TRUE, &local_c, FALSE},
- {"remote", TRUE, &remote_c, !ask},
+ {"remote", TRUE, &remote_c, !nmc->ask},
{"dev", TRUE, &parent_c, FALSE},
{NULL} };
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!mode_c && ask)
+ if (!mode_c && nmc->ask)
mode_c = mode_ask = nmc_readline (PROMPT_IP_TUNNEL_MODE);
if (!mode_c) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -6310,7 +6442,7 @@ cleanup_tun:
goto cleanup_tunnel;
}
- if (!remote_c && ask)
+ if (!remote_c && nmc->ask)
remote_c = remote_ask = nmc_readline (_("Remote endpoint: "));
if (!remote_c) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -6328,7 +6460,7 @@ cleanup_tun:
local = g_strdup (local_c);
parent = g_strdup (parent_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_ip_tunnel (&local, &parent);
if ( local
@@ -6392,8 +6524,8 @@ cleanup_tunnel:
unsigned long int vni;
unsigned long sport_min = G_MAXULONG, sport_max = G_MAXULONG;
unsigned long dport = G_MAXULONG;
- nmc_arg_t exp_args[] = { {"id", TRUE, &id, !ask},
- {"remote", TRUE, &remote, !ask},
+ nmc_arg_t exp_args[] = { {"id", TRUE, &id, !nmc->ask},
+ {"remote", TRUE, &remote, !nmc->ask},
{"dev", TRUE, &parent_c, FALSE},
{"local", TRUE, &local_c, FALSE},
{"source-port-min", TRUE, &src_port_min_c, FALSE},
@@ -6404,7 +6536,7 @@ cleanup_tunnel:
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!id && ask)
+ if (!id && nmc->ask)
id = id_ask = nmc_readline (_("VXLAN ID: "));
if (!id) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -6412,7 +6544,7 @@ cleanup_tunnel:
goto cleanup_vxlan;
}
- if (!remote && ask)
+ if (!remote && nmc->ask)
remote = remote_ask = nmc_readline (_("Remote: "));
if (!remote) {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -6432,7 +6564,7 @@ cleanup_tunnel:
src_port_max = g_strdup (src_port_max_c);
dst_port = g_strdup (dst_port_c);
- if (ask)
+ if (nmc->ask)
do_questionnaire_vxlan (&parent, &local, &src_port_min, &src_port_max, &dst_port);
if (parent) {
@@ -6617,7 +6749,7 @@ cleanup_vxlan:
}
/* Ask for addresses if '--ask' is specified. */
- if (ask)
+ if (nmc->ask)
do_questionnaire_ip (connection);
}
@@ -6629,7 +6761,7 @@ cleanup_vxlan:
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
return FALSE;
- if (!read_connection_properties (connection, argc, argv, error))
+ if (!read_connection_properties (nmc, connection, argc, argv, error))
return FALSE;
}
@@ -6922,7 +7054,10 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
rl_attempted_completion_function = (rl_completion_func_t *) nmcli_con_add_tab_completion;
- nmc->return_value = NMC_RESULT_SUCCESS;
+ if (nmc->complete) {
+ /* Add support to properties and arg completion */
+ return nmc->return_value;
+ }
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, &error)) {
g_string_assign (nmc->return_text, error->message);
@@ -7041,11 +7176,9 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
g_free (default_name);
nm_connection_add_setting (connection, NM_SETTING (s_con));
- if (!complete_connection_by_type (connection,
+ if (!complete_connection_by_type (nmc,
+ connection,
setting_name,
- nmc->connections,
- nmc->ask,
- nmc->show_secrets,
argc,
argv,
&error)) {
@@ -10129,9 +10262,13 @@ do_connection_modify (NmCli *nmc,
const char *selector = NULL;
GError *error = NULL;
- nmc->return_value = NMC_RESULT_SUCCESS;
-
if (argc == 0) {
+ /*
+ * TODO(?) complete "uuid", "path", "id" or connection name.
+ * (if we ever will move this here from shell completion script)
+ if (nmc->complete) {
+ quit ();
+ */
g_string_printf (nmc->return_text, _("Error: No arguments provided."));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto finish;
@@ -10142,6 +10279,12 @@ do_connection_modify (NmCli *nmc,
selector = *argv;
if (next_arg (&argc, &argv) != 0) {
+ /*
+ * TODO(?): complete uuid, path or id
+ if (nmc->complete) {
+ quit ();
+ }
+ */
g_string_printf (nmc->return_text, _("Error: %s argument is missing."),
selector);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
@@ -10150,11 +10293,7 @@ do_connection_modify (NmCli *nmc,
name = *argv;
}
name = *argv;
- if (!name) {
- g_string_printf (nmc->return_text, _("Error: connection ID is missing."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
+
connection = nmc_find_connection (nmc->connections, selector, name, NULL);
if (!connection) {
g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), name);
@@ -10170,22 +10309,31 @@ do_connection_modify (NmCli *nmc,
}
if (next_arg (&argc, &argv) != 0) {
+ if (nmc->complete) {
+ complete_property_name (nmc, NM_CONNECTION (rc), '\0', "", NULL);
+ goto finish;
+ }
g_string_printf (nmc->return_text, _("Error: <setting>.<property> argument is missing."));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto finish;
}
- if (!read_connection_properties (NM_CONNECTION (rc), argc, argv, &error)) {
+ if (!read_connection_properties (nmc, NM_CONNECTION (rc), argc, argv, &error)) {
g_string_assign (nmc->return_text, error->message);
nmc->return_value = error->code;
g_clear_error (&error);
goto finish;
}
- update_connection (!temporary, rc, modify_connection_cb, nmc);
+ if (!nmc->complete) {
+ update_connection (!temporary, rc, modify_connection_cb, nmc);
+ nmc->should_wait++;
+ }
- nmc->should_wait++;
finish:
+ /* shell completion - be sure to exit with success without printing errors */
+ if (nmc->complete)
+ nmc->return_value = NMC_RESULT_SUCCESS;
return nmc->return_value;
}
@@ -10243,6 +10391,10 @@ do_connection_clone (NmCli *nmc, gboolean temporary, int argc, char **argv)
const char *selector = NULL;
char *uuid;
+ /* Not (yet?) supported */
+ if (nmc->complete)
+ return nmc->return_value;
+
if (argc == 0) {
if (nmc->ask) {
name = name_ask = nmc_readline (PROMPT_CONNECTION);
@@ -10366,6 +10518,10 @@ do_connection_delete (NmCli *nmc, int argc, char **argv)
GString *invalid_cons = NULL;
int pos = 0;
+ /* Not (yet?) supported */
+ if (nmc->complete)
+ return nmc->return_value;
+
if (nmc->timeout == -1)
nmc->timeout = 10;
@@ -10498,6 +10654,11 @@ connection_removed (NMClient *client, NMRemoteConnection *con, NmCli *nmc)
static NMCResultCode
do_connection_monitor (NmCli *nmc, int argc, char **argv)
{
+
+ /* Not (yet?) supported */
+ if (nmc->complete)
+ return nmc->return_value;
+
if (argc == 0) {
/* No connections specified. Monitor all. */
int i;
@@ -10554,7 +10715,9 @@ do_connection_reload (NmCli *nmc, int argc, char **argv)
{
GError *error = NULL;
- nmc->return_value = NMC_RESULT_SUCCESS;
+ /* Not (yet?) supported */
+ if (nmc->complete)
+ return nmc->return_value;
if (!nm_client_reload_connections (nmc->client, NULL, &error)) {
g_string_printf (nmc->return_text, _("Error: failed to reload connections: %s."),
@@ -10573,7 +10736,9 @@ do_connection_load (NmCli *nmc, int argc, char **argv)
char **filenames, **failures = NULL;
int i;
- nmc->return_value = NMC_RESULT_SUCCESS;
+ /* Not (yet?) supported */
+ if (nmc->complete)
+ return nmc->return_value;
if (argc == 0) {
g_string_printf (nmc->return_text, _("Error: No connection specified."));
@@ -10619,6 +10784,10 @@ do_connection_import (NmCli *nmc, gboolean temporary, int argc, char **argv)
NMVpnEditorPlugin *plugin;
gs_free char *service_type = NULL;
+ /* Not (yet?) supported */
+ if (nmc->complete)
+ return nmc->return_value;
+
if (argc == 0) {
if (nmc->ask) {
type_ask = nmc_readline (PROMPT_IMPORT_TYPE);
@@ -10735,6 +10904,10 @@ do_connection_export (NmCli *nmc, int argc, char **argv)
GError *error = NULL;
char tmpfile[] = "/tmp/nmcli-export-temp-XXXXXX";
+ /* Not (yet?) supported */
+ if (nmc->complete)
+ return nmc->return_value;
+
if (argc == 0) {
if (nmc->ask) {
name_ask = nmc_readline (PROMPT_VPN_CONNECTION);
@@ -11044,8 +11217,10 @@ do_connections (NmCli *nmc, int argc, char **argv)
/* Check whether NetworkManager is running */
if (!nm_client_get_nm_running (nmc->client)) {
- g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
- nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+ if (!nmc->complete) {
+ g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+ nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+ }
return nmc->return_value;
}
@@ -11100,6 +11275,9 @@ do_connections (NmCli *nmc, int argc, char **argv)
} else if (matches(*argv, "add") == 0) {
nmc->return_value = do_connection_add (nmc, argc-1, argv+1);
} else if (matches(*argv, "edit") == 0) {
+ /* edit with --complete? Should not happen */
+ if (nmc->complete)
+ goto opt_error;
nmc->should_wait++;
editor_thread_data.nmc = nmc;
editor_thread_data.argc = argc - 1;
@@ -11117,6 +11295,8 @@ do_connections (NmCli *nmc, int argc, char **argv)
next_arg (&argc, &argv);
if (nmc_arg_is_option (*argv, "temporary")) {
+ if (nmc->complete)
+ goto opt_error;
temporary = TRUE;
next_arg (&argc, &argv);
}
@@ -11126,6 +11306,8 @@ do_connections (NmCli *nmc, int argc, char **argv)
next_arg (&argc, &argv);
if (nmc_arg_is_option (*argv, "temporary")) {
+ if (nmc->complete)
+ goto opt_error;
temporary = TRUE;
next_arg (&argc, &argv);
}
@@ -11135,6 +11317,8 @@ do_connections (NmCli *nmc, int argc, char **argv)
next_arg (&argc, &argv);
if (nmc_arg_is_option (*argv, "temporary")) {
+ if (nmc->complete)
+ goto opt_error;
temporary = TRUE;
next_arg (&argc, &argv);
}
@@ -11144,6 +11328,8 @@ do_connections (NmCli *nmc, int argc, char **argv)
} else if (matches(*argv, "monitor") == 0) {
nmc->return_value = do_connection_monitor (nmc, argc-1, argv+1);
} else {
+ if (nmc->complete)
+ goto opt_error;
usage ();
g_string_printf (nmc->return_text, _("Error: '%s' is not valid 'connection' command."), *argv);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
@@ -11153,8 +11339,10 @@ do_connections (NmCli *nmc, int argc, char **argv)
return nmc->return_value;
opt_error:
- g_string_printf (nmc->return_text, _("Error: %s."), error->message);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ if (!nmc->complete) {
+ g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ }
g_error_free (error);
return nmc->return_value;
}
diff --git a/clients/cli/nmcli-completion b/clients/cli/nmcli-completion
index ffab7d8b99..d5bd80de5c 100644
--- a/clients/cli/nmcli-completion
+++ b/clients/cli/nmcli-completion
@@ -231,14 +231,14 @@ _nmcli_compl_OPTIONS()
mode)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "tabular multiline"
- return 0
+ return 0
fi
_nmcli_array_delete_at words 0 1
;;
colors)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "yes no auto"
- return 0
+ return 0
fi
_nmcli_array_delete_at words 0 1
;;
@@ -249,21 +249,21 @@ _nmcli_compl_OPTIONS()
connection 802-3-ethernet 802-1x 802-11-wireless 802-11-wireless-security ipv4 ipv6 serial ppp pppoe gsm cdma bluetooth 802-11-olpc-mesh vpn wimax infiniband bond vlan adsl bridge bridge-port team team-port dcb tun ip-tunnel macvlan vxlan
GENERAL IP4 DHCP4 IP6 DHCP6 VPN
profile active"
- return 0
+ return 0
fi
_nmcli_array_delete_at words 0 1
;;
escape)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "no yes"
- return 0
+ return 0
fi
_nmcli_array_delete_at words 0 1
;;
wait)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list ""
- return 0
+ return 0
fi
_nmcli_array_delete_at words 0 1
;;
@@ -761,21 +761,14 @@ _nmcli_compl_COMMAND_nl() {
_nmcli_compl_PROPERTIES()
{
- while [[ "${#words[@]}" -gt 0 ]]; do
- if [[ ${#words[@]} -le 1 ]]; then
- local PREFIX=""
-
- if [[ "${words[0]:0:1}" == [+-] ]]; then
- PREFIX="${words[0]:0:1}"
- fi
- _nmcli_list_nl "$(echo -e 'print\nquit\nyes' |nmcli c edit "$@" 2>/dev/null |awk -F: '/\..*:/ {print "'$PREFIX'"$1}')"
- return 0
- elif [[ ${#words[@]} -le 2 ]]; then
+ while [[ ${#words[@]} -gt 0 ]]; do
+ if [[ ${#words[@]} -eq 1 ]]; then
+ _nmcli_list_nl "$(nmcli --complete-args connection modify "$@" "${words[@]}" 2>/dev/null)"
return 0
fi
_nmcli_array_delete_at words 0 1
done
- _nmcli_list_nl "$(echo -e 'print\nquit\nyes' |nmcli c edit "$@" 2>/dev/null |awk -F: '/\..*:/ {print $1}')"
+ return 0
}
_nmcli()
@@ -802,22 +795,18 @@ _nmcli()
cur=''
fi
- local OPTIONS_UNKNOWN_OPTION OPTIONS_TYPE OPTIONS_TYPED OPTIONS OPTIONS_MANDATORY COMMAND_ARGS_WAIT_OPTIONS OPTIONS_IP OPTIONS_MANDATORY OPTIONS_NEXT_GROUP OPTIONS_SEP OPTIONS_REPEATABLE
- local COMMAND_CONNECTION_TYPE COMMAND_CONNECTION_ID OPTIONS_MANDATORY_IFNAME HELP_ONLY_AS_FIRST
- local COMMAND_CONNECTION_ACTIVE=""
+ local OPTIONS OPTIONS_UNKNOWN_OPTION OPTIONS_TYPE OPTIONS_TYPED OPTIONS_IP OPTIONS_NEXT_GROUP \
+ OPTIONS_SEP OPTIONS_REPEATABLE OPTIONS_MANDATORY OPTIONS_MANDATORY_IFNAME \
+ COMMAND_ARGS_WAIT_OPTIONS COMMAND_CONNECTION_TYPE COMMAND_CONNECTION_ID \
+ COMMAND_CONNECTION_ACTIVE="" HELP_ONLY_AS_FIRST="" \
+ LONG_OPTIONS=(terse pretty mode fields colors escape ask show-secrets wait version help)
- HELP_ONLY_AS_FIRST=
- local LONG_OPTIONS=(terse pretty mode fields colors escape ask show-secrets wait version help)
_nmcli_compl_OPTIONS
i=$?
- if [[ "$HELP_ONLY_AS_FIRST" == '0' ]]; then
- # got a --help. No more completion.
- return 0
- fi
-
case $i in
0)
+ # We have just completed an option or got an --help: terminate.
return 0
;;
1)
diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c
index 7e788654d5..84bb4a23df 100644
--- a/clients/cli/nmcli.c
+++ b/clients/cli/nmcli.c
@@ -154,7 +154,18 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
base = argv[0];
else
base++;
-
+ if (argc > 1 && nm_streq (argv[1], "--complete-args")) {
+ /* We (currently?) support --complete-args for "connection" command only:
+ * ignore any other command when this option is enabled as means we are in
+ * autocompletion mode (so we should just quit and don't print anything).
+ * This would help us to ensure shell autocompletion after NM package downgrade
+ * if we ever will enable --complete-args for other commands */
+ if ((argc == 2) || !nm_streq0 (argv[2], "connection"))
+ return nmc->return_value;
+ nmc->complete = TRUE;
+ argv[1] = argv[0];
+ argc--; argv++;
+ }
/* parse options */
while (argc > 1) {
char *opt = argv[1];
@@ -545,6 +556,7 @@ nmc_init (NmCli *nmc)
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;
diff --git a/clients/cli/nmcli.h b/clients/cli/nmcli.h
index 34100f0026..c867ad5f9f 100644
--- a/clients/cli/nmcli.h
+++ b/clients/cli/nmcli.h
@@ -153,6 +153,7 @@ typedef struct _NmCli {
GPtrArray *output_data; /* GPtrArray of arrays of NmcOutputField structs - accumulates data for output */
NmcPrintFields print_fields; /* Structure with field indices to print */
gboolean ask; /* Ask for missing parameters: option '--ask' */
+ gboolean complete; /* Autocomplete the command line */
gboolean show_secrets; /* Whether to display secrets (both input and output): option '--show-secrets' */
gboolean in_editor; /* Whether running the editor - nmcli con edit' */
gboolean editor_status_line; /* Whether to display status line in connection editor */