about summary refs log tree commit diff
path: root/clients/cli/nmcli.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2016-08-26 02:18:32 +0200
committerMichael Biebl <biebl@debian.org>2016-08-26 02:18:32 +0200
commit7514efc2f38c9ace4557d4e69d68e7d380389030 (patch)
tree7fb00fda86cfcc2ca377f191633a7cfdbfea7ca3 /clients/cli/nmcli.c
parentd6201f5d8daada3d64a0a3e0038e14eebec683ce (diff)
Imported Upstream version 1.4.0 upstream/1.4.0
Diffstat (limited to 'clients/cli/nmcli.c')
-rw-r--r--clients/cli/nmcli.c256
1 files changed, 174 insertions, 82 deletions
diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c
index 7e788654..8bc8828b 100644
--- a/clients/cli/nmcli.c
+++ b/clients/cli/nmcli.c
@@ -19,7 +19,6 @@
  * Copyright 2010 - 2015 Red Hat, Inc.
  */
 
-/* Generated configuration file */
 #include "nm-default.h"
 
 #include <stdio.h>
@@ -41,6 +40,7 @@
 #include "devices.h"
 #include "general.h"
 #include "agent.h"
+#include "settings.h"
 
 #if defined(NM_DIST_VERSION)
 # define NMCLI_VERSION NM_DIST_VERSION
@@ -64,6 +64,105 @@ GMainLoop *loop = NULL;
 static sigset_t signal_set;
 struct termios termios_orig;
 
+static void
+complete_field (GHashTable *h, const char *setting, NmcOutputField field[])
+{
+	int 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));
+	}
+}
+
+static void
+complete_one (gpointer key, gpointer value, gpointer user_data)
+{
+	const char *prefix = user_data;
+	const char *name = key;
+	const char *last;
+
+	last = strrchr (prefix, ',');
+	if (last)
+		last++;
+	else
+		last = prefix;
+
+	if ((!*last && !strchr (name, '.')) || matches (last, name) == 0) {
+		g_print ("%.*s%s%s\n", (int)(last-prefix), prefix, name,
+		                       strcmp (last, name) == 0 ? "," : "");
+	}
+}
+
+static void
+complete_fields (const char *prefix)
+{
+
+	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, "wired", nmc_fields_setting_wired);
+	complete_field (h, "8021X", nmc_fields_setting_8021X);
+	complete_field (h, "wireless", nmc_fields_setting_wireless);
+	complete_field (h, "wireless_security", nmc_fields_setting_wireless_security);
+	complete_field (h, "ip4-config", nmc_fields_setting_ip4_config);
+	complete_field (h, "ip6-config", 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, "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, "team0port", 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);
+	g_hash_table_destroy (h);
+}
+
 
 /* Get an error quark for use with GError */
 GQuark
@@ -78,9 +177,9 @@ nmcli_error_quark (void)
 }
 
 static void
-usage (const char *prog_name)
+usage (void)
 {
-	g_printerr (_("Usage: %s [OPTIONS] OBJECT { COMMAND | help }\n"
+	g_printerr (_("Usage: nmcli [OPTIONS] OBJECT { COMMAND | help }\n"
 	              "\n"
 	              "OPTIONS\n"
 	              "  -t[erse]                                   terse output\n"
@@ -103,48 +202,21 @@ usage (const char *prog_name)
 	              "  d[evice]        devices managed by NetworkManager\n"
 	              "  a[gent]         NetworkManager secret agent or polkit agent\n"
 	              "  m[onitor]       monitor NetworkManager changes\n"
-	              "\n"),
-	            prog_name);
-}
-
-static NMCResultCode 
-do_help (NmCli *nmc, int argc, char **argv)
-{
-	usage ("nmcli");
-	return NMC_RESULT_SUCCESS;
+	              "\n"));
 }
 
-static const struct cmd {
-	const char *cmd;
-	NMCResultCode (*func) (NmCli *nmc, int argc, char **argv);
-} nmcli_cmds[] = {
-	{ "general",    do_general },
-	{ "monitor",    do_monitor },
-	{ "networking", do_networking },
-	{ "radio",      do_radio },
-	{ "connection", do_connections },
-	{ "device",     do_devices },
-	{ "agent",      do_agent },
-	{ "help",       do_help },
-	{ 0 }
+static const NMCCommand nmcli_cmds[] = {
+	{ "general",    do_general,     NULL },
+	{ "monitor",    do_monitor,     NULL },
+	{ "networking", do_networking,  NULL },
+	{ "radio",      do_radio,       NULL },
+	{ "connection", do_connections, NULL },
+	{ "device",     do_devices,     NULL },
+	{ "agent",      do_agent,       NULL },
+	{ NULL,         do_overview,    usage }
 };
 
 static NMCResultCode
-do_cmd (NmCli *nmc, const char *argv0, int argc, char **argv)
-{
-	const struct cmd *c;
-
-	for (c = nmcli_cmds; c->cmd; ++c) {
-		if (matches (argv0, c->cmd) == 0)
-			return c->func (nmc, argc-1, argv+1);
-	}
-
-	g_string_printf (nmc->return_text, _("Error: Object '%s' is unknown, try 'nmcli help'."), argv0);
-	nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-	return nmc->return_value;
-}
-
-static NMCResultCode
 parse_command_line (NmCli *nmc, int argc, char **argv)
 {
 	char *base;
@@ -154,19 +226,34 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 		base = argv[0];
 	else
 		base++;
+	if (argc > 1 && nm_streq (argv[1], "--complete-args")) {
+		nmc->complete = TRUE;
+		argv[1] = argv[0];
+		argc--; argv++;
+	}
+	argc--; argv++;
 
 	/* parse options */
-	while (argc > 1) {
-		char *opt = argv[1];
-		/* '--' ends options */
-		if (strcmp (opt, "--") == 0) {
-			argc--; argv++;
-			break;
-		}
+	while (argc) {
+		char *opt = argv[0];
 		if (opt[0] != '-')
 			break;
-		if (opt[1] == '-')
+
+		if (argc == 1 && nmc->complete) {
+			nmc_complete_strings (opt, "--terse", "--pretty", "--mode", "--colors", "--escape",
+			                           "--fields", "--nocheck", "--ask", "--show-secrets",
+			                           "--wait", "--version", "--help", NULL);
+		}
+
+		if (opt[1] == '-') {
 			opt++;
+			/* '--' ends options */
+			if (opt[1] == '\0') {
+				argc--; argv++;
+				break;
+			}
+		}
+
 		if (matches (opt, "-terse") == 0) {
 			if (nmc->print_output == NMC_PRINT_TERSE) {
 				g_string_printf (nmc->return_text, _("Error: Option '--terse' is specified the second time."));
@@ -195,63 +282,67 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 				nmc->print_output = NMC_PRINT_PRETTY;
 		} else if (matches (opt, "-mode") == 0) {
 			nmc->mode_specified = TRUE;
-			next_arg (&argc, &argv);
-			if (argc <= 1) {
+			if (next_arg (&argc, &argv) != 0) {
 		 		g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				return nmc->return_value;
 			}
-			if (matches (argv[1], "tabular") == 0)
+			if (argc == 1 && nmc->complete)
+				nmc_complete_strings (argv[0], "tabular", "multiline", NULL);
+			if (matches (argv[0], "tabular") == 0)
 				nmc->multiline_output = FALSE;
-			else if (matches (argv[1], "multiline") == 0)
+			else if (matches (argv[0], "multiline") == 0)
 				nmc->multiline_output = TRUE;
 			else {
-		 		g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[1], opt);
+		 		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 nmc->return_value;
 			}
 		} else if (matches (opt, "-colors") == 0) {
-			next_arg (&argc, &argv);
-			if (argc <= 1) {
+			if (next_arg (&argc, &argv) != 0) {
 		 		g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				return nmc->return_value;
 			}
-			if (matches (argv[1], "auto") == 0)
+			if (argc == 1 && nmc->complete)
+				nmc_complete_strings (argv[0], "yes", "no", "auto", NULL);
+			if (matches (argv[0], "auto") == 0)
 				nmc->use_colors = NMC_USE_COLOR_AUTO;
-			else if (matches (argv[1], "yes") == 0)
+			else if (matches (argv[0], "yes") == 0)
 				nmc->use_colors = NMC_USE_COLOR_YES;
-			else if (matches (argv[1], "no") == 0)
+			else if (matches (argv[0], "no") == 0)
 				nmc->use_colors = NMC_USE_COLOR_NO;
 			else {
-		 		g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[1], opt);
+		 		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 nmc->return_value;
 			}
 		} else if (matches (opt, "-escape") == 0) {
-			next_arg (&argc, &argv);
-			if (argc <= 1) {
+			if (next_arg (&argc, &argv) != 0) {
 		 		g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				return nmc->return_value;
 			}
-			if (matches (argv[1], "yes") == 0)
+			if (argc == 1 && nmc->complete)
+				nmc_complete_strings (argv[0], "yes", "no", NULL);
+			if (matches (argv[0], "yes") == 0)
 				nmc->escape_values = TRUE;
-			else if (matches (argv[1], "no") == 0)
+			else if (matches (argv[0], "no") == 0)
 				nmc->escape_values = FALSE;
 			else {
-		 		g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), argv[1], opt);
+		 		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 nmc->return_value;
 			}
 		} else if (matches (opt, "-fields") == 0) {
-			next_arg (&argc, &argv);
-			if (argc <= 1) {
+			if (next_arg (&argc, &argv) != 0) {
 		 		g_string_printf (nmc->return_text, _("Error: fields for '%s' options are missing."), opt);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				return nmc->return_value;
 			}
-			nmc->required_fields = g_strdup (argv[1]);
+			if (argc == 1 && nmc->complete)
+				complete_fields (argv[0]);
+			nmc->required_fields = g_strdup (argv[0]);
 		} else if (matches (opt, "-nocheck") == 0) {
 			/* ignore for backward compatibility */
 		} else if (matches (opt, "-ask") == 0) {
@@ -260,24 +351,25 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 			nmc->show_secrets = TRUE;
 		} else if (matches (opt, "-wait") == 0) {
 			unsigned long timeout;
-			next_arg (&argc, &argv);
-			if (argc <= 1) {
+			if (next_arg (&argc, &argv) != 0) {
 		 		g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				return nmc->return_value;
 			}
-			if (!nmc_string_to_uint (argv[1], TRUE, 0, G_MAXINT, &timeout)) {
+			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[1], opt);
+				                 argv[0], opt);
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 				return nmc->return_value;
 			}
 			nmc->timeout = (int) timeout;
 		} else if (matches (opt, "-version") == 0) {
-			g_print (_("nmcli tool, version %s\n"), NMCLI_VERSION);
+			if (!nmc->complete)
+				g_print (_("nmcli tool, version %s\n"), NMCLI_VERSION);
 			return NMC_RESULT_SUCCESS;
 		} else if (matches (opt, "-help") == 0) {
-			usage (base);
+			if (!nmc->complete)
+				usage ();
 			return NMC_RESULT_SUCCESS;
 		} else {
 			g_string_printf (nmc->return_text, _("Error: Option '%s' is unknown, try 'nmcli -help'."), opt);
@@ -288,13 +380,8 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
 		argv++;
 	}
 
-	if (argc > 1) {
-		/* Now run the requested command */
-		return do_cmd (nmc, argv[1], argc-1, argv+1);
-	}
-
-	usage (base);
-	return nmc->return_value;
+	/* Now run the requested command */
+	return nmc_do_cmd (nmc, nmcli_cmds, *argv, argc, argv);
 }
 
 static gboolean nmcli_sigint = FALSE;
@@ -545,6 +632,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;
@@ -628,8 +716,12 @@ main (int argc, char *argv[])
 	loop = g_main_loop_new (NULL, FALSE);  /* create main loop */
 	g_main_loop_run (loop);                /* run main loop */
 
-	/* Print result descripting text */
-	if (nm_cli.return_value != NMC_RESULT_SUCCESS) {
+	if (nm_cli.complete) {
+		/* Remove error statuses from command completion runs. */
+		if (nm_cli.return_value < NMC_RESULT_COMPLETE_FILE)
+			nm_cli.return_value = NMC_RESULT_SUCCESS;
+	} else if (nm_cli.return_value != NMC_RESULT_SUCCESS) {
+		/* Print result descripting text */
 		g_printerr ("%s\n", nm_cli.return_text->str);
 	}