summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2016-08-01 16:11:35 +0200
committerLubomir Rintel <lkundrak@v3.sk>2016-08-01 16:11:35 +0200
commit2956fd5fcb26635c42ad3fa738d06ffb722acfa1 (patch)
treeb7c51eb32100db114cdaa0d47bec4225623fa249
parent570e8ee29684f16b4306f1eb94a1b756608ddd3b (diff)
parent8cc6ce7e44d574cc8baf0dbb3737f6ada060ae99 (diff)
downloadNetworkManager-2956fd5fcb26635c42ad3fa738d06ffb722acfa1.tar.gz
merge: branch 'lr/completion-2'
https://bugzilla.gnome.org/show_bug.cgi?id=768737
-rw-r--r--clients/cli/agent.c53
-rw-r--r--clients/cli/common.c53
-rw-r--r--clients/cli/common.h8
-rw-r--r--clients/cli/connections.c1018
-rw-r--r--clients/cli/connections.h6
-rw-r--r--clients/cli/devices.c482
-rw-r--r--clients/cli/devices.h20
-rw-r--r--clients/cli/general.c423
-rw-r--r--clients/cli/nmcli.c219
-rw-r--r--clients/cli/nmcli.h5
-rw-r--r--clients/cli/settings.c6
-rw-r--r--clients/cli/settings.h30
-rw-r--r--man/nmcli.xml24
13 files changed, 1254 insertions, 1093 deletions
diff --git a/clients/cli/agent.c b/clients/cli/agent.c
index b8a56d2381..bc837c722f 100644
--- a/clients/cli/agent.c
+++ b/clients/cli/agent.c
@@ -138,6 +138,9 @@ secrets_requested (NMSecretAgentSimple *agent,
static NMCResultCode
do_agent_secret (NmCli *nmc, int argc, char **argv)
{
+ if (nmc->complete)
+ return nmc->return_value;
+
/* Create secret agent */
nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-agent");
if (nmc->secret_agent) {
@@ -160,6 +163,9 @@ do_agent_polkit (NmCli *nmc, int argc, char **argv)
{
GError *error = NULL;
+ if (nmc->complete)
+ return nmc->return_value;
+
/* Initialize polkit agent */
if (!nmc_polkit_agent_init (nmc, TRUE, &error)) {
g_dbus_error_strip_remote_error (error);
@@ -182,6 +188,9 @@ do_agent_all (NmCli *nmc, int argc, char **argv)
{
NMCResultCode secret_res;
+ if (nmc->complete)
+ return nmc->return_value;
+
/* Run both secret and polkit agent */
secret_res = do_agent_secret (nmc, argc, argv);
if (secret_res != NMC_RESULT_SUCCESS)
@@ -195,6 +204,14 @@ do_agent_all (NmCli *nmc, int argc, char **argv)
return nmc->return_value;
}
+static const NMCCommand agent_cmds[] = {
+ {"secret", do_agent_secret, usage_agent_secret },
+ {"polkit", do_agent_polkit, usage_agent_polkit },
+ {"all", do_agent_all, usage_agent_all },
+ {NULL, do_agent_all, usage }
+};
+
+
NMCResultCode
do_agent (NmCli *nmc, int argc, char **argv)
{
@@ -208,39 +225,5 @@ do_agent (NmCli *nmc, int argc, char **argv)
return nmc->return_value;
}
- if (argc == 0) {
- nmc->return_value = do_agent_all (nmc, 0, NULL);
- }
-
- if (argc > 0) {
- if (nmc_arg_is_help (*argv)) {
- usage ();
- goto usage_exit;
- } else if (matches (*argv, "secret") == 0) {
- if (nmc_arg_is_help (*(argv+1))) {
- usage_agent_secret ();
- goto usage_exit;
- }
- nmc->return_value = do_agent_secret (nmc, argc-1, argv+1);
- } else if (matches (*argv, "polkit") == 0) {
- if (nmc_arg_is_help (*(argv+1))) {
- usage_agent_polkit ();
- goto usage_exit;
- }
- nmc->return_value = do_agent_polkit (nmc, argc-1, argv+1);
- } else if (matches (*argv, "all") == 0) {
- if (nmc_arg_is_help (*(argv+1))) {
- usage_agent_all ();
- goto usage_exit;
- }
- nmc->return_value = do_agent_all (nmc, argc-1, argv+1);
- } else {
- usage ();
- g_string_printf (nmc->return_text, _("Error: 'agent' command '%s' is not valid."), *argv);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- }
- }
-
-usage_exit:
- return nmc->return_value;
+ return nmc_do_cmd (nmc, agent_cmds, *argv, argc, argv);
}
diff --git a/clients/cli/common.c b/clients/cli/common.c
index 7ac0a7625d..8b4a6aede5 100644
--- a/clients/cli/common.c
+++ b/clients/cli/common.c
@@ -872,6 +872,7 @@ nmc_team_check_config (const char *config, char **out_config, GError **error)
* @filter_val: connection to find (connection name, UUID or path)
* @start: where to start in @list. The location is updated so that the function
* can be called multiple times (for connections with the same name).
+ * @complete: print possible completions
*
* Find a connection in @list according to @filter_val. @filter_type determines
* what property is used for comparison. When @filter_type is NULL, compare
@@ -885,7 +886,8 @@ NMConnection *
nmc_find_connection (const GPtrArray *connections,
const char *filter_type,
const char *filter_val,
- int *start)
+ int *start,
+ gboolean complete)
{
NMConnection *connection;
NMConnection *found = NULL;
@@ -907,20 +909,36 @@ nmc_find_connection (const GPtrArray *connections,
* type. If 'path' filter type is specified, comparison against
* numeric index (in addition to the whole path) is allowed.
*/
- if ( ( (!filter_type || strcmp (filter_type, "id") == 0)
- && strcmp (filter_val, id) == 0)
- || ( (!filter_type || strcmp (filter_type, "uuid") == 0)
- && strcmp (filter_val, uuid) == 0)
- || ( (!filter_type || strcmp (filter_type, "path") == 0)
- && (g_strcmp0 (filter_val, path) == 0 || (filter_type && g_strcmp0 (filter_val, path_num) == 0)))) {
- if (!start)
- return connection;
- if (found) {
- *start = i;
- return found;
- }
- found = connection;
+ if (!filter_type || strcmp (filter_type, "id") == 0) {
+ if (complete)
+ nmc_complete_strings (filter_val, id, NULL);
+ if (strcmp (filter_val, id) == 0)
+ goto found;
+ }
+
+ if (!filter_type || strcmp (filter_type, "uuid") == 0) {
+ if (complete && (filter_type || *filter_val))
+ nmc_complete_strings (filter_val, uuid, NULL);
+ if (strcmp (filter_val, uuid) == 0)
+ goto found;
+ }
+
+ if (!filter_type || strcmp (filter_type, "path") == 0) {
+ if (complete && (filter_type || *filter_val))
+ nmc_complete_strings (filter_val, path, filter_type ? path_num : NULL, NULL);
+ if (g_strcmp0 (filter_val, path) == 0 || (filter_type && g_strcmp0 (filter_val, path_num) == 0))
+ goto found;
}
+
+ continue;
+found:
+ if (!start)
+ return connection;
+ if (found) {
+ *start = i;
+ return found;
+ }
+ found = connection;
}
if (start)
@@ -1096,7 +1114,7 @@ nmc_secrets_requested (NMSecretAgentSimple *agent,
p = strrchr (path, '/');
if (p)
*p = '\0';
- connection = nmc_find_connection (nmc->connections, "path", path, NULL);
+ connection = nmc_find_connection (nmc->connections, "path", path, NULL, FALSE);
g_free (path);
}
@@ -1416,6 +1434,9 @@ nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char
{
const NMCCommand *c;
+ if (argc == 0 && nmc->complete)
+ return nmc->return_value;
+
if (argc == 1 && nmc->complete) {
for (c = cmds; c->cmd; ++c) {
if (!*cmd || matches (cmd, c->cmd) == 0)
@@ -1445,7 +1466,7 @@ nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char
}
} else if (c->func) {
/* No command, run the default handler. */
- nmc->return_value = c->func (nmc, argc-1, argv+1);
+ nmc->return_value = c->func (nmc, argc, argv);
} else {
/* No command and no default handler. */
g_string_printf (nmc->return_text, _("Error: missing argument. Try passing --help."));
diff --git a/clients/cli/common.h b/clients/cli/common.h
index 3910683dc5..2450cdb950 100644
--- a/clients/cli/common.h
+++ b/clients/cli/common.h
@@ -48,7 +48,8 @@ gboolean nmc_team_check_config (const char *config, char **out_config, GError **
NMConnection *nmc_find_connection (const GPtrArray *connections,
const char *filter_type,
const char *filter_val,
- int *start);
+ int *start,
+ gboolean complete);
void nmc_secrets_requested (NMSecretAgentSimple *agent,
const char *request_id,
@@ -85,4 +86,9 @@ void nmc_complete_strings (const char *prefix, ...) G_GNUC_NULL_TERMINATED;
void nmc_complete_bool (const char *prefix);
+extern NmcOutputField nmc_fields_ip4_config[];
+extern NmcOutputField nmc_fields_dhcp4_config[];
+extern NmcOutputField nmc_fields_ip6_config[];
+extern NmcOutputField nmc_fields_dhcp6_config[];
+
#endif /* NMC_COMMON_H */
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index 10b7df77f2..53e57e4eed 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -33,6 +33,7 @@
#include "common.h"
#include "settings.h"
#include "connections.h"
+#include "devices.h"
#include "nm-secret-agent-simple.h"
#include "polkit-agent.h"
#include "nm-vpn-helpers.h"
@@ -114,7 +115,7 @@ struct _OptionInfo {
#define BASE_PROMPT "nmcli> "
/* Available fields for 'connection show' */
-static NmcOutputField nmc_fields_con_show[] = {
+NmcOutputField nmc_fields_con_show[] = {
{"NAME", N_("NAME")}, /* 0 */
{"UUID", N_("UUID")}, /* 1 */
{"TYPE", N_("TYPE")}, /* 2 */
@@ -137,39 +138,8 @@ static NmcOutputField nmc_fields_con_show[] = {
/* Helper macro to define fields */
#define SETTING_FIELD(setting, props) { setting, N_(setting), 0, props, NULL, FALSE, FALSE, 0 }
-/* defined in settings.c */
-extern NmcOutputField nmc_fields_setting_connection[];
-extern NmcOutputField nmc_fields_setting_wired[];
-extern NmcOutputField nmc_fields_setting_8021X[];
-extern NmcOutputField nmc_fields_setting_wireless[];
-extern NmcOutputField nmc_fields_setting_wireless_security[];
-extern NmcOutputField nmc_fields_setting_ip4_config[];
-extern NmcOutputField nmc_fields_setting_ip6_config[];
-extern NmcOutputField nmc_fields_setting_serial[];
-extern NmcOutputField nmc_fields_setting_ppp[];
-extern NmcOutputField nmc_fields_setting_pppoe[];
-extern NmcOutputField nmc_fields_setting_adsl[];
-extern NmcOutputField nmc_fields_setting_gsm[];
-extern NmcOutputField nmc_fields_setting_cdma[];
-extern NmcOutputField nmc_fields_setting_bluetooth[];
-extern NmcOutputField nmc_fields_setting_olpc_mesh[];
-extern NmcOutputField nmc_fields_setting_vpn[];
-extern NmcOutputField nmc_fields_setting_wimax[];
-extern NmcOutputField nmc_fields_setting_infiniband[];
-extern NmcOutputField nmc_fields_setting_bond[];
-extern NmcOutputField nmc_fields_setting_vlan[];
-extern NmcOutputField nmc_fields_setting_bridge[];
-extern NmcOutputField nmc_fields_setting_bridge_port[];
-extern NmcOutputField nmc_fields_setting_team[];
-extern NmcOutputField nmc_fields_setting_team_port[];
-extern NmcOutputField nmc_fields_setting_dcb[];
-extern NmcOutputField nmc_fields_setting_tun[];
-extern NmcOutputField nmc_fields_setting_ip_tunnel[];
-extern NmcOutputField nmc_fields_setting_macvlan[];
-extern NmcOutputField nmc_fields_setting_vxlan[];
-
/* Available settings for 'connection show <con>' - profile part */
-static NmcOutputField nmc_fields_settings_names[] = {
+NmcOutputField nmc_fields_settings_names[] = {
SETTING_FIELD (NM_SETTING_CONNECTION_SETTING_NAME, nmc_fields_setting_connection + 1), /* 0 */
SETTING_FIELD (NM_SETTING_WIRED_SETTING_NAME, nmc_fields_setting_wired + 1), /* 1 */
SETTING_FIELD (NM_SETTING_802_1X_SETTING_NAME, nmc_fields_setting_8021X + 1), /* 2 */
@@ -233,7 +203,7 @@ static NmcOutputField nmc_fields_settings_names[] = {
/* Active connection data */
/* Available fields for GENERAL group */
-static NmcOutputField nmc_fields_con_active_details_general[] = {
+NmcOutputField nmc_fields_con_active_details_general[] = {
{"GROUP", N_("GROUP")}, /* 0 */
{"NAME", N_("NAME")}, /* 1 */
{"UUID", N_("UUID")}, /* 2 */
@@ -255,7 +225,7 @@ static NmcOutputField nmc_fields_con_active_details_general[] = {
/* IP group is handled by common.c */
/* Available fields for VPN group */
-static NmcOutputField nmc_fields_con_active_details_vpn[] = {
+NmcOutputField nmc_fields_con_active_details_vpn[] = {
{"GROUP", N_("GROUP")}, /* 0 */
{"TYPE", N_("TYPE")}, /* 1 */
{"USERNAME", N_("USERNAME")}, /* 2 */
@@ -274,7 +244,7 @@ extern NmcOutputField nmc_fields_dhcp4_config[];
extern NmcOutputField nmc_fields_dhcp6_config[];
/* Available fields for 'connection show <con>' - active part */
-static NmcOutputField nmc_fields_con_active_details_groups[] = {
+NmcOutputField nmc_fields_con_active_details_groups[] = {
{"GENERAL", N_("GENERAL"), 0, nmc_fields_con_active_details_general + 1}, /* 0 */
{"IP4", N_("IP4"), 0, nmc_fields_ip4_config + 1 }, /* 1 */
{"DHCP4", N_("DHCP4"), 0, nmc_fields_dhcp4_config + 1 }, /* 2 */
@@ -613,42 +583,6 @@ usage_connection_export (void)
"The data are directed to standard output or to a file if a name is given.\n\n"));
}
-static gboolean
-usage_connection_second_level (const char *cmd)
-{
- gboolean ret = TRUE;
-
- if (matches (cmd, "show") == 0)
- usage_connection_show ();
- else if (matches (cmd, "up") == 0)
- usage_connection_up ();
- else if (matches (cmd, "down") == 0)
- usage_connection_down ();
- else if (matches (cmd, "add") == 0)
- usage_connection_add ();
- else if (matches (cmd, "modify") == 0)
- usage_connection_modify ();
- else if (matches (cmd, "clone") == 0)
- usage_connection_clone ();
- else if (matches (cmd, "edit") == 0)
- usage_connection_edit ();
- else if (matches (cmd, "delete") == 0)
- usage_connection_delete ();
- else if (matches (cmd, "monitor") == 0)
- usage_connection_monitor ();
- else if (matches (cmd, "reload") == 0)
- usage_connection_reload ();
- else if (matches (cmd, "load") == 0)
- usage_connection_load ();
- else if (matches (cmd, "import") == 0)
- usage_connection_import ();
- else if (matches (cmd, "export") == 0)
- usage_connection_export ();
- else
- ret = FALSE;
- return ret;
-}
-
/* quit main loop */
static void
quit (void)
@@ -864,7 +798,8 @@ find_active_connection (const GPtrArray *active_cons,
const GPtrArray *cons,
const char *filter_type,
const char *filter_val,
- int *idx)
+ int *idx,
+ gboolean complete)
{
int i;
int start = (idx && *idx > 0) ? *idx : 0;
@@ -891,22 +826,43 @@ find_active_connection (const GPtrArray *active_cons,
* type. If 'path' or 'apath' filter types are specified, comparison
* against numeric index (in addition to the whole path) is allowed.
*/
- if ( ( (!filter_type || strcmp (filter_type, "id") == 0)
- && strcmp (filter_val, id) == 0)
- || ( (!filter_type || strcmp (filter_type, "uuid") == 0)
- && strcmp (filter_val, uuid) == 0)
- || ( (!filter_type || strcmp (filter_type, "path") == 0)
- && (g_strcmp0 (filter_val, path) == 0 || (filter_type && g_strcmp0 (filter_val, path_num) == 0)))
- || ( (!filter_type || strcmp (filter_type, "apath") == 0)
- && (g_strcmp0 (filter_val, a_path) == 0 || (filter_type && g_strcmp0 (filter_val, a_path_num) == 0)))) {
- if (!idx)
- return candidate;
- if (found) {
- *idx = i;
- return found;
- }
- found = candidate;
+ if (!filter_type || strcmp (filter_type, "id") == 0) {
+ if (complete)
+ nmc_complete_strings (filter_val, id, NULL);
+ if (strcmp (filter_val, id) == 0)
+ goto found;
+ }
+
+ if (!filter_type || strcmp (filter_type, "uuid") == 0) {
+ if (complete && (filter_type || *filter_val))
+ nmc_complete_strings (filter_val, uuid, NULL);
+ if (strcmp (filter_val, uuid) == 0)
+ goto found;
+ }
+
+ if (!filter_type || strcmp (filter_type, "path") == 0) {
+ if (complete && (filter_type || *filter_val))
+ nmc_complete_strings (filter_val, path, filter_type ? path_num : NULL, NULL);
+ if (g_strcmp0 (filter_val, path) == 0 || (filter_type && g_strcmp0 (filter_val, path_num) == 0))
+ goto found;
}
+
+ if (!filter_type || strcmp (filter_type, "apath") == 0) {
+ if (complete && (filter_type || *filter_val))
+ nmc_complete_strings (filter_val, a_path, filter_type ? a_path_num : NULL, NULL);
+ if (g_strcmp0 (filter_val, a_path) == 0 || (filter_type && g_strcmp0 (filter_val, a_path_num) == 0))
+ goto found;
+ }
+
+ continue;
+found:
+ if (!idx)
+ return candidate;
+ if (found) {
+ *idx = i;
+ return found;
+ }
+ found = candidate;
}
if (idx)
@@ -1649,17 +1605,146 @@ get_invisible_active_connections (NmCli *nmc)
return invisibles;
}
+static GArray *
+parse_preferred_connection_order (const char *order, GError **error)
+{
+ char **strv, **iter;
+ const char *str;
+ GArray *order_arr;
+ NmcSortOrder val;
+ gboolean inverse, unique;
+ int i;
+
+ strv = nmc_strsplit_set (order, ":", -1);
+ if (!strv || !*strv) {
+ g_set_error (error, NMCLI_ERROR, 0,
+ _("incorrect string '%s' of '--order' option"), order);
+ g_strfreev (strv);
+ return NULL;
+ }
+
+ order_arr = g_array_sized_new (FALSE, FALSE, sizeof (NmcSortOrder), 4);
+ for (iter = strv; iter && *iter; iter++) {
+ str = *iter;
+ inverse = FALSE;
+ if (str[0] == '-')
+ inverse = TRUE;
+ if (str[0] == '+' || str[0] == '-')
+ str++;
+
+ if (matches (str, "active") == 0)
+ val = inverse ? NMC_SORT_ACTIVE_INV : NMC_SORT_ACTIVE;
+ else if (matches (str, "name") == 0)
+ val = inverse ? NMC_SORT_NAME_INV : NMC_SORT_NAME;
+ else if (matches (str, "type") == 0)
+ val = inverse ? NMC_SORT_TYPE_INV : NMC_SORT_TYPE;
+ else if (matches (str, "path") == 0)
+ val = inverse ? NMC_SORT_PATH_INV : NMC_SORT_PATH;
+ else {
+ g_array_unref (order_arr);
+ order_arr = NULL;
+ g_set_error (error, NMCLI_ERROR, 0,
+ _("incorrect item '%s' in '--order' option"), *iter);
+ break;
+ }
+ /* Check for duplicates and ignore them. */
+ unique = TRUE;
+ for (i = 0; i < order_arr->len; i++) {
+ if (abs (g_array_index (order_arr, NmcSortOrder, i)) - abs (val) == 0) {
+ unique = FALSE;
+ break;
+ }
+ }
+
+ /* Value is ok and unique, add it to the array */
+ if (unique)
+ g_array_append_val (order_arr, val);
+ }
+
+ g_strfreev (strv);
+ return order_arr;
+}
+
+static NMConnection *
+get_connection (NmCli *nmc, int *argc, char ***argv, int *pos, GError **error)
+{
+ NMConnection *connection = NULL;
+ const char *selector = NULL;
+
+ if (*argc == 0) {
+ g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("No connection specified"));
+ return NULL;
+ }
+
+ if (*argc == 1 && nmc->complete)
+ nmc_complete_strings (**argv, "id", "uuid", "path", NULL);
+
+ if ( strcmp (**argv, "id") == 0
+ || strcmp (**argv, "uuid") == 0
+ || strcmp (**argv, "path") == 0) {
+ selector = **argv;
+ if (next_arg (argc, argv) != 0) {
+ g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("%s argument is missing"), selector);
+ return NULL;
+ }
+ }
+
+ connection = nmc_find_connection (nmc->connections, selector, **argv, pos,
+ *argc == 1 && nmc->complete);
+ if (!connection) {
+ g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_NOT_FOUND,
+ _("unknown connection '%s'"), **argv);
+ }
+
+ next_arg (argc, argv);
+
+ return connection;
+}
+
static NMCResultCode
-do_connections_show (NmCli *nmc, gboolean active_only, gboolean show_secrets,
- const GArray *order, int argc, char **argv)
+do_connections_show (NmCli *nmc, int argc, char **argv)
{
GError *err = NULL;
char *profile_flds = NULL, *active_flds = NULL;
GPtrArray *invisibles, *sorted_cons;
+ gboolean active_only = FALSE;
+ gboolean show_secrets = FALSE;
+ GArray *order = NULL;
+ int i;
- /* Not (yet?) supported */
- if (nmc->complete)
- goto finish;
+ /* check connection show options [--active] [--show-secrets] */
+ for (i = 0; i < 3; i++) {
+ if (argc == 1 && nmc->complete) {
+ nmc_complete_strings (*argv, "--active", "--show-secrets",
+ "--order", NULL);
+ }
+
+ if (!active_only && nmc_arg_is_option (*argv, "active")) {
+ active_only = TRUE;
+ next_arg (&argc, &argv);
+ } else if (!show_secrets && nmc_arg_is_option (*argv, "show-secrets")) {
+ /* --show-secrets is deprecated in favour of global --show-secrets */
+ /* Keep it here for backwards compatibility */
+ show_secrets = TRUE;
+ next_arg (&argc, &argv);
+ } else if (!order && nmc_arg_is_option (*argv, "order")) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_set_error_literal (&err, NMCLI_ERROR, 0,
+ _("'--order' argument is missing"));
+ goto finish;
+ }
+ /* TODO: complete --order */
+ order = parse_preferred_connection_order (*argv, &err);
+ if (err)
+ goto finish;
+ next_arg (&argc, &argv);
+ } else {
+ break;
+ }
+ }
+ show_secrets = nmc->show_secrets || show_secrets;
if (argc == 0) {
char *fields_str;
@@ -1667,7 +1752,9 @@ do_connections_show (NmCli *nmc, gboolean active_only, gboolean show_secrets,
char *fields_common = NMC_FIELDS_CON_SHOW_COMMON;
NmcOutputField *tmpl, *arr;
size_t tmpl_len;
- int i;
+
+ if (nmc->complete)
+ goto finish;
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
fields_str = fields_common;
@@ -1727,6 +1814,9 @@ do_connections_show (NmCli *nmc, gboolean active_only, gboolean show_secrets,
NMActiveConnection *acon = NULL;
const char *selector = NULL;
+ if (argc == 1 && nmc->complete)
+ nmc_complete_strings (*argv, "id", "uuid", "path", "apath", NULL);
+
if ( strcmp (*argv, "id") == 0
|| strcmp (*argv, "uuid") == 0
|| strcmp (*argv, "path") == 0
@@ -1739,10 +1829,13 @@ do_connections_show (NmCli *nmc, gboolean active_only, gboolean show_secrets,
}
}
- /* Find connection by id, uuid, path or apath */
- con = nmc_find_connection (nmc->connections, selector, *argv, &pos);
- if (!con) {
- acon = find_active_connection (active_cons, nmc->connections, selector, *argv, NULL);
+ /* Try to find connection by id, uuid or path first */
+ con = nmc_find_connection (nmc->connections, selector, *argv, &pos,
+ argc == 1 && nmc->complete);
+ if (!con && (!selector || strcmp (selector, "apath") == 0)) {
+ /* Try apath too */
+ acon = find_active_connection (active_cons, nmc->connections, "apath", *argv, NULL,
+ argc == 1 && nmc->complete);
if (acon)
con = NM_CONNECTION (nm_active_connection_get_connection (acon));
}
@@ -1767,6 +1860,11 @@ do_connections_show (NmCli *nmc, gboolean active_only, gboolean show_secrets,
continue;
}
+ if (nmc->complete) {
+ next_arg (&argc, &argv);
+ continue;
+ }
+
/* Show an empty line between connections */
if (new_line)
g_print ("\n");
@@ -1813,6 +1911,8 @@ finish:
}
g_free (profile_flds);
g_free (active_flds);
+ if (order)
+ g_array_unref (order);
return nmc->return_value;
}
@@ -2456,14 +2556,12 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
const char *ap = NULL;
const char *nsp = NULL;
const char *pwds = NULL;
- GError *error = NULL;
- const char *selector = NULL;
- const char *name = NULL;
- char *line = NULL;
+ gs_free_error GError *error = NULL;
+ char **arg_arr = NULL;
+ int arg_num;
+ char ***argv_ptr = &argv;
+ int *argc_ptr = &argc;
- /* 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.
@@ -2471,66 +2569,63 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
if (nmc->timeout == -1)
nmc->timeout = 90;
- if (argc == 0) {
- if (nmc->ask) {
- line = nmc_readline (PROMPT_CONNECTION);
- name = line ? line : "";
- }
- } else if (strcmp (*argv, "ifname") != 0) {
- if ( strcmp (*argv, "id") == 0
- || strcmp (*argv, "uuid") == 0
- || strcmp (*argv, "path") == 0) {
+ if (argc == 0 && nmc->ask) {
+ char *line;
- selector = *argv;
- if (next_arg (&argc, &argv) != 0) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
- }
- name = *argv;
- }
- name = *argv;
- next_arg (&argc, &argv);
+ /* nmc_do_cmd() should not call this with argc=0. */
+ g_assert (!nmc->complete);
+
+ line = nmc_readline ("%s: ", PROMPT_CONNECTION);
+ nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
+ g_free (line);
+ argv_ptr = &arg_arr;
+ argc_ptr = &arg_num;
}
- if (name) {
- connection = nmc_find_connection (nmc->connections, selector, name, NULL);
+ if (argc > 0 && strcmp (*argv, "ifname") != 0) {
+ connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, &error);
if (!connection) {
- g_string_printf (nmc->return_text, _("Error: Connection '%s' does not exist."), name);
- nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
- goto error;
+ g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+ return error->code;
}
}
while (argc > 0) {
+ if (argc == 1 && nmc->complete)
+ nmc_complete_strings (*argv, "ifname", "ap", "passwd-file", NULL);
+
if (strcmp (*argv, "ifname") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
ifname = *argv;
+ if (argc == 1 && nmc->complete)
+ nmc_complete_device (nmc->client, ifname, ap != NULL);
}
else if (strcmp (*argv, "ap") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
ap = *argv;
+ if (argc == 1 && nmc->complete)
+ nmc_complete_bssid (nmc->client, ifname, ap);
}
else if (strcmp (*argv, "passwd-file") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
+ if (argc == 1 && nmc->complete)
+ nmc->return_value = NMC_RESULT_COMPLETE_FILE;
+
pwds = *argv;
}
- else {
+ else if (!nmc->complete) {
g_printerr (_("Unknown parameter: %s\n"), *argv);
}
@@ -2538,6 +2633,9 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
argv++;
}
+ if (nmc->complete)
+ return nmc->return_value;
+
/* Use nowait_flag instead of should_wait because exiting has to be postponed till
* active_connection_state_cb() is called. That gives NM time to check our permissions
* and we can follow activation progress.
@@ -2548,18 +2646,14 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
if (!nmc_activate_connection (nmc, connection, ifname, ap, nsp, pwds, activate_connection_cb, &error)) {
g_string_printf (nmc->return_text, _("Error: %s."),
error->message);
- nmc->return_value = error->code;
- g_clear_error (&error);
nmc->should_wait--;
- goto error;
+ return error->code;
}
/* Start progress indication */
if (nmc->print_output == NMC_PRINT_PRETTY)
progress_id = g_timeout_add (120, progress_cb, _("preparing"));
-error:
- g_free (line);
return nmc->return_value;
}
@@ -2653,14 +2747,13 @@ 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;
if (argc == 0) {
+ /* nmc_do_cmd() should not call this with argc=0. */
+ g_assert (!nmc->complete);
+
if (nmc->ask) {
char *line = nmc_readline (PROMPT_ACTIVE_CONNECTIONS);
nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
@@ -2670,7 +2763,7 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
if (arg_num == 0) {
g_string_printf (nmc->return_text, _("Error: No connection specified."));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
}
@@ -2679,6 +2772,9 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
while (arg_num > 0) {
const char *selector = NULL;
+ if (arg_num == 1)
+ nmc_complete_strings (*arg_ptr, "id", "uuid", "path", "apath", NULL);
+
if ( strcmp (*arg_ptr, "id") == 0
|| strcmp (*arg_ptr, "uuid") == 0
|| strcmp (*arg_ptr, "path") == 0
@@ -2688,11 +2784,12 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
if (next_arg (&arg_num, &arg_ptr) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
}
- active = find_active_connection (active_cons, nmc->connections, selector, *arg_ptr, &idx);
+ active = find_active_connection (active_cons, nmc->connections, selector, *arg_ptr, &idx,
+ arg_num == 1 && nmc->complete);
if (active) {
/* Check if the connection is unique. */
/* Calling down for the same connection repeatedly would result in
@@ -2700,7 +2797,8 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
if (!g_slist_find (queue, active))
queue = g_slist_prepend (queue, g_object_ref (active));
} else {
- g_printerr (_("Error: '%s' is not an active connection.\n"), *arg_ptr);
+ if (!nmc->complete)
+ g_printerr (_("Error: '%s' is not an active connection.\n"), *arg_ptr);
g_string_printf (nmc->return_text, _("Error: not all active connections found."));
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
}
@@ -2712,7 +2810,10 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
if (!queue) {
g_string_printf (nmc->return_text, _("Error: no active connection provided."));
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
- goto error;
+ goto finish;
+ } else if (nmc->complete) {
+ g_slist_free (queue);
+ goto finish;
}
queue = g_slist_reverse (queue);
@@ -2738,7 +2839,7 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
nm_client_deactivate_connection (nmc->client, active, NULL, NULL);
}
-error:
+finish:
g_strfreev (arg_arr);
return nmc->return_value;
}
@@ -4813,7 +4914,7 @@ uuid_display_hook (char **array, int len, int max_len)
char *tmp;
const char *id;
for (i = 1; i <= len; i++) {
- con = nmc_find_connection (nmc_tab_completion.nmc->connections, "uuid", array[i], NULL);
+ con = nmc_find_connection (nmc_tab_completion.nmc->connections, "uuid", array[i], NULL, FALSE);
id = con ? nm_connection_get_id (con) : NULL;
if (id) {
tmp = g_strdup_printf ("%s (%s)", array[i], id);
@@ -7575,7 +7676,7 @@ editor_init_existing_connection (NMConnection *connection)
}
static NMCResultCode
-do_connection_edit (NmCli *nmc, int argc, char **argv)
+do_connection_edit_func (NmCli *nmc, int argc, char **argv)
{
NMConnection *connection = NULL;
NMSettingConnection *s_con;
@@ -7600,6 +7701,10 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
{"path", TRUE, &con_path, FALSE},
{NULL} };
+ /* TODO: complete uuid, path or id */
+ if (nmc->complete)
+ return nmc->return_value;
+
nmc->return_value = NMC_RESULT_SUCCESS;
if (argc == 1)
@@ -7643,7 +7748,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
/* Existing connection */
NMConnection *found_con;
- found_con = nmc_find_connection (nmc->connections, selector, con, NULL);
+ found_con = nmc_find_connection (nmc->connections, selector, con, NULL, FALSE);
if (!found_con) {
g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), con);
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
@@ -7756,6 +7861,46 @@ error:
return nmc->return_value;
}
+typedef struct {
+ NmCli *nmc;
+ int argc;
+ char **argv;
+} NmcEditorThreadData;
+
+static GThread *editor_thread;
+static NmcEditorThreadData editor_thread_data;
+
+/*
+ * We need to run do_connection_edit_func() in a thread so that
+ * glib main loop is not blocked and could receive and process D-Bus
+ * return messages.
+ */
+static gpointer
+connection_editor_thread_func (gpointer data)
+{
+ NmcEditorThreadData *td = (NmcEditorThreadData *) data;
+
+ /* run editor for editing/adding connections */
+ td->nmc->return_value = do_connection_edit_func (td->nmc, td->argc, td->argv);
+
+ /* quit glib main loop now that we are done with this thread */
+ quit ();
+
+ return NULL;
+}
+
+static NMCResultCode
+do_connection_edit (NmCli *nmc, int argc, char **argv)
+{
+ nmc->should_wait++;
+ editor_thread_data.nmc = nmc;
+ editor_thread_data.argc = argc;
+ editor_thread_data.argv = argv;
+ editor_thread = g_thread_new ("editor-thread", connection_editor_thread_func, &editor_thread_data);
+ g_thread_unref (editor_thread);
+
+ return nmc->return_value;
+}
static void
modify_connection_cb (GObject *connection,
@@ -7784,58 +7929,33 @@ modify_connection_cb (GObject *connection,
static NMCResultCode
do_connection_modify (NmCli *nmc,
- gboolean temporary,
int argc,
char **argv)
{
NMConnection *connection = NULL;
NMRemoteConnection *rc = NULL;
- const char *name;
- const char *selector = NULL;
GError *error = NULL;
+ gboolean temporary = FALSE;
- 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;
- }
- if ( strcmp (*argv, "id") == 0
- || strcmp (*argv, "uuid") == 0
- || strcmp (*argv, "path") == 0) {
-
- 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;
+ if (argc && nmc_arg_is_option (*argv, "temporary")) {
+ if (nmc->complete)
goto finish;
- }
- name = *argv;
+ temporary = TRUE;
+ next_arg (&argc, &argv);
}
- name = *argv;
- connection = nmc_find_connection (nmc->connections, selector, name, NULL);
+ connection = get_connection (nmc, &argc, &argv, NULL, &error);
if (!connection) {
- g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), name);
- nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+ g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+ nmc->return_value = error->code;
goto finish;
}
+
rc = nm_client_get_connection_by_uuid (nmc->client,
nm_connection_get_uuid (connection));
if (!rc) {
- g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), name);
+ g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."),
+ nm_connection_get_uuid (connection));
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
goto finish;
}
@@ -7900,74 +8020,64 @@ clone_connection_cb (GObject *client,
}
static NMCResultCode
-do_connection_clone (NmCli *nmc, gboolean temporary, int argc, char **argv)
+do_connection_clone (NmCli *nmc, int argc, char **argv)
{
NMConnection *connection = NULL;
NMConnection *new_connection = NULL;
NMSettingConnection *s_con;
CloneConnectionInfo *info;
- const char *name;
const char *new_name;
- char *name_ask = NULL;
char *new_name_ask = NULL;
- const char *selector = NULL;
char *uuid;
+ gboolean temporary = FALSE;
+ char **arg_arr = NULL;
+ int arg_num;
+ char ***argv_ptr = &argv;
+ int *argc_ptr = &argc;
+ GError *error = NULL;
- /* Not (yet?) supported */
- if (nmc->complete)
- return nmc->return_value;
+ if (argc == 1 && nmc->complete)
+ nmc_complete_strings (*argv, "temporary", NULL);
- if (argc == 0) {
- if (nmc->ask) {
- name = name_ask = nmc_readline (PROMPT_CONNECTION);
- new_name = new_name_ask = nmc_readline (_("New connection name: "));
- } else {
- g_string_printf (nmc->return_text, _("Error: No arguments provided."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
- } else {
- if ( strcmp (*argv, "id") == 0
- || strcmp (*argv, "uuid") == 0
- || strcmp (*argv, "path") == 0) {
+ if (argc == 0 && nmc->ask) {
+ char *line;
- selector = *argv;
- if (next_arg (&argc, &argv) != 0) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."),
- selector);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
- }
- name = *argv;
- if (next_arg (&argc, &argv) != 0) {
- g_string_printf (nmc->return_text, _("Error: <new name> argument is missing."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
- new_name = *argv;
- if (next_arg (&argc, &argv) == 0) {
- g_string_printf (nmc->return_text, _("Error: unexpected extra argument '%s'."), *argv);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
+ /* nmc_do_cmd() should not call this with argc=0. */
+ g_assert (!nmc->complete);
+
+ line = nmc_readline ("%s: ", PROMPT_CONNECTION);
+ nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
+ g_free (line);
+ argv_ptr = &arg_arr;
+ argc_ptr = &arg_num;
+ } else if (nmc_arg_is_option (*argv, "temporary")) {
+ temporary = TRUE;
+ next_arg (&argc, &argv);
}
- if (!name) {
- g_string_printf (nmc->return_text, _("Error: connection ID is missing."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, &error);
+ if (!connection) {
+ g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+ nmc->return_value = error->code;
goto finish;
}
- if (!new_name) {
+
+ if (nmc->complete)
+ goto finish;
+
+ if (next_arg (&argc, &argv) == 0)
+ new_name = *argv;
+ else if (nmc->ask)
+ new_name = new_name_ask = nmc_readline (_("New connection name: "));
+ else {
g_string_printf (nmc->return_text, _("Error: <new name> argument 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);
- nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+ if (next_arg (argc_ptr, argv_ptr) == 0) {
+ g_string_printf (nmc->return_text, _("Error: unknown extra argument: '%s'."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto finish;
}
@@ -8003,7 +8113,6 @@ do_connection_clone (NmCli *nmc, gboolean temporary, int argc, char **argv)
finish:
if (new_connection)
g_object_unref (new_connection);
- g_free (name_ask);
g_free (new_name_ask);
return nmc->return_value;
@@ -8039,43 +8148,32 @@ do_connection_delete (NmCli *nmc, int argc, char **argv)
int arg_num = argc;
GString *invalid_cons = NULL;
int pos = 0;
-
- /* Not (yet?) supported */
- if (nmc->complete)
- return nmc->return_value;
+ GError *error = NULL;
if (nmc->timeout == -1)
nmc->timeout = 10;
if (argc == 0) {
if (nmc->ask) {
- char *line = nmc_readline (PROMPT_CONNECTIONS);
+ char *line;
+
+ /* nmc_do_cmd() should not call this with argc=0. */
+ g_assert (!nmc->complete);
+
+ line = nmc_readline ("%s: ", PROMPT_CONNECTIONS);
nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
g_free (line);
arg_ptr = arg_arr;
}
if (arg_num == 0) {
g_string_printf (nmc->return_text, _("Error: No connection specified."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
goto finish;
}
}
while (arg_num > 0) {
- const char *selector = NULL;
-
- if ( strcmp (*arg_ptr, "id") == 0
- || strcmp (*arg_ptr, "uuid") == 0
- || strcmp (*arg_ptr, "path") == 0) {
- selector = *arg_ptr;
- if (next_arg (&arg_num, &arg_ptr) != 0) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
- }
-
- connection = nmc_find_connection (nmc->connections, selector, *arg_ptr, &pos);
+ connection = get_connection (nmc, &arg_num, &arg_ptr, &pos, &error);
if (connection) {
/* Check if the connection is unique. */
/* Calling delete for the same connection repeatedly would result in
@@ -8083,9 +8181,15 @@ do_connection_delete (NmCli *nmc, int argc, char **argv)
if (!g_slist_find (queue, connection))
queue = g_slist_prepend (queue, g_object_ref (connection));
} else {
- g_printerr (_("Error: unknown connection '%s'\n"), *arg_ptr);
- g_string_printf (nmc->return_text, _("Error: not all active connections found."));
- nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+ if (!nmc->complete)
+ g_printerr (_("Error: %s.\n"), error->message);
+ g_string_printf (nmc->return_text, _("Error: not all connections found."));
+ nmc->return_value = error->code;
+ g_clear_error (&error);
+
+ if (nmc->return_value != NMC_RESULT_ERROR_NOT_FOUND)
+ goto finish;
+
if (!invalid_cons)
invalid_cons = g_string_new (NULL);
g_string_append_printf (invalid_cons, "'%s', ", *arg_ptr);
@@ -8097,9 +8201,12 @@ do_connection_delete (NmCli *nmc, int argc, char **argv)
}
if (!queue) {
- g_string_printf (nmc->return_text, _("Error: no connection provided."));
+ g_string_printf (nmc->return_text, _("Error: No connection specified."));
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
goto finish;
+ } else if (nmc->complete) {
+ g_slist_free (queue);
+ goto finish;
}
queue = g_slist_reverse (queue);
@@ -8176,15 +8283,15 @@ 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;
+ GError *error = NULL;
if (argc == 0) {
/* No connections specified. Monitor all. */
int i;
+ /* nmc_do_cmd() should not call this with argc=0. */
+ g_assert (!nmc->complete);
+
nmc->connections = nm_client_get_connections (nmc->client);
for (i = 0; i < nmc->connections->len; i++)
connection_watch (nmc, g_ptr_array_index (nmc->connections, i));
@@ -8195,38 +8302,29 @@ do_connection_monitor (NmCli *nmc, int argc, char **argv)
} else {
/* Look up the specified connections and watch them. */
NMConnection *connection;
- char **arg_ptr = argv;
- int arg_num = argc;
int pos = 0;
do {
- const char *selector = NULL;
-
- if ( strcmp (*arg_ptr, "id") == 0
- || strcmp (*arg_ptr, "uuid") == 0
- || strcmp (*arg_ptr, "path") == 0) {
- selector = *arg_ptr;
- if (next_arg (&arg_num, &arg_ptr) != 0) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
- return NMC_RESULT_ERROR_USER_INPUT;
- }
- }
-
- connection = nmc_find_connection (nmc->connections, selector, *arg_ptr, &pos);
- if (connection) {
- connection_watch (nmc, connection);
- } else {
- g_printerr (_("Error: unknown connection '%s'\n"), *arg_ptr);
+ connection = get_connection (nmc, &argc, &argv, &pos, &error);
+ if (!connection) {
+ if (!nmc->complete)
+ g_printerr (_("Error: %s.\n"), error->message);
g_string_printf (nmc->return_text, _("Error: not all connections found."));
- return NMC_RESULT_ERROR_NOT_FOUND;
+ return error->code;
}
-
/* Take next argument (if there's no other connection of the same name) */
if (!pos)
- next_arg (&arg_num, &arg_ptr);
- } while (arg_num > 0);
+ next_arg (&argc, &argv);
+
+ if (nmc->complete)
+ continue;
+
+ connection_watch (nmc, connection);
+ } while (argc > 0);
}
+ if (nmc->complete)
+ return nmc->return_value;
g_signal_connect (nmc->client, NM_CLIENT_CONNECTION_REMOVED, G_CALLBACK (connection_removed), nmc);
return NMC_RESULT_SUCCESS;
@@ -8237,7 +8335,6 @@ do_connection_reload (NmCli *nmc, int argc, char **argv)
{
GError *error = NULL;
- /* Not (yet?) supported */
if (nmc->complete)
return nmc->return_value;
@@ -8258,16 +8355,14 @@ do_connection_load (NmCli *nmc, int argc, char **argv)
char **filenames, **failures = NULL;
int i;
- /* Not (yet?) supported */
- if (nmc->complete)
- return nmc->return_value;
-
if (argc == 0) {
g_string_printf (nmc->return_text, _("Error: No connection specified."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return nmc->return_value;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
+ if (nmc->complete)
+ return NMC_RESULT_COMPLETE_FILE;
+
filenames = g_new (char *, argc + 1);
for (i = 0; i < argc; i++)
filenames[i] = argv[i];
@@ -8296,7 +8391,7 @@ do_connection_load (NmCli *nmc, int argc, char **argv)
#define PROMPT_IMPORT_FILE N_("File to import: ")
static NMCResultCode
-do_connection_import (NmCli *nmc, gboolean temporary, int argc, char **argv)
+do_connection_import (NmCli *nmc, int argc, char **argv)
{
GError *error = NULL;
const char *type = NULL, *filename = NULL;
@@ -8305,12 +8400,12 @@ do_connection_import (NmCli *nmc, gboolean temporary, int argc, char **argv)
NMConnection *connection = NULL;
NMVpnEditorPlugin *plugin;
gs_free char *service_type = NULL;
-
- /* Not (yet?) supported */
- if (nmc->complete)
- return nmc->return_value;
+ gboolean temporary = FALSE;
if (argc == 0) {
+ /* nmc_do_cmd() should not call this with argc=0. */
+ g_assert (!nmc->complete);
+
if (nmc->ask) {
type_ask = nmc_readline (gettext (PROMPT_IMPORT_TYPE));
filename_ask = nmc_readline (gettext (PROMPT_IMPORT_FILE));
@@ -8324,6 +8419,13 @@ do_connection_import (NmCli *nmc, gboolean temporary, int argc, char **argv)
}
while (argc > 0) {
+ if (argc == 1 && nmc->complete)
+ nmc_complete_strings (*argv, "temporary", "type", "file", NULL);
+ if (nmc_arg_is_option (*argv, "temporary")) {
+ temporary = TRUE;
+ next_arg (&argc, &argv);
+ }
+
if (strcmp (*argv, "type") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
@@ -8341,6 +8443,8 @@ do_connection_import (NmCli *nmc, gboolean temporary, int argc, char **argv)
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto finish;
}
+ if (argc == 1 && nmc->complete)
+ nmc->return_value = NMC_RESULT_COMPLETE_FILE;
if (!filename)
filename = *argv;
else
@@ -8355,6 +8459,9 @@ do_connection_import (NmCli *nmc, gboolean temporary, int argc, char **argv)
argv++;
}
+ if (nmc->complete)
+ goto finish;
+
if (!type) {
g_string_printf (nmc->return_text, _("Error: 'type' argument is required."));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
@@ -8415,64 +8522,50 @@ static NMCResultCode
do_connection_export (NmCli *nmc, int argc, char **argv)
{
NMConnection *connection = NULL;
- const char *name;
const char *out_name = NULL;
char *name_ask = NULL;
char *out_name_ask = NULL;
const char *path = NULL;
- const char *selector = NULL;
const char *type = NULL;
NMVpnEditorPlugin *plugin;
GError *error = NULL;
char tmpfile[] = "/tmp/nmcli-export-temp-XXXXXX";
+ char **arg_arr = NULL;
+ int arg_num;
+ char ***argv_ptr = &argv;
+ int *argc_ptr = &argc;
- /* Not (yet?) supported */
- if (nmc->complete)
- return nmc->return_value;
-
- if (argc == 0) {
- if (nmc->ask) {
- name_ask = nmc_readline (PROMPT_VPN_CONNECTION);
- name = name_ask = name_ask ? g_strstrip (name_ask) : NULL;
- out_name = out_name_ask = nmc_readline (_("Output file name: "));
- } else {
- g_string_printf (nmc->return_text, _("Error: No arguments provided."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
- } else {
- if ( strcmp (*argv, "id") == 0
- || strcmp (*argv, "uuid") == 0
- || strcmp (*argv, "path") == 0) {
+ if (argc == 0 && nmc->ask) {
+ char *line;
- selector = *argv;
- if (next_arg (&argc, &argv) != 0) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."),
- selector);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
- }
- name = *argv;
- if (next_arg (&argc, &argv) == 0)
- out_name = *argv;
+ /* nmc_do_cmd() should not call this with argc=0. */
+ g_assert (!nmc->complete);
- if (next_arg (&argc, &argv) == 0) {
- g_string_printf (nmc->return_text, _("Error: unknown extra argument: '%s'."), *argv);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
+ line = nmc_readline ("%s: ", PROMPT_VPN_CONNECTION);
+ nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
+ g_free (line);
+ argv_ptr = &arg_arr;
+ argc_ptr = &arg_num;
}
- if (!name) {
- g_string_printf (nmc->return_text, _("Error: connection ID is missing."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, &error);
+ if (!connection) {
+ g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+ nmc->return_value = error->code;
goto finish;
}
- connection = nmc_find_connection (nmc->connections, selector, name, NULL);
- if (!connection) {
- g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), name);
- nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+
+ if (nmc->complete)
+ return nmc->return_value;
+
+ if (next_arg (&argc, &argv) == 0)
+ out_name = *argv;
+ else if (nmc->ask)
+ out_name = out_name_ask = nmc_readline (_("Output file name: "));
+
+ if (next_arg (argc_ptr, argv_ptr) == 0) {
+ g_string_printf (nmc->return_text, _("Error: unknown extra argument: '%s'."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto finish;
}
@@ -8537,35 +8630,6 @@ finish:
return nmc->return_value;
}
-
-typedef struct {
- NmCli *nmc;
- int argc;
- char **argv;
-} NmcEditorThreadData;
-
-static GThread *editor_thread;
-static NmcEditorThreadData editor_thread_data;
-
-/*
- * We need to run do_connection_edit() in a thread so that
- * glib main loop is not blocked and could receive and process D-Bus
- * return messages.
- */
-static gpointer
-connection_editor_thread_func (gpointer data)
-{
- NmcEditorThreadData *td = (NmcEditorThreadData *) data;
-
- /* run editor for editing/adding connections */
- td->nmc->return_value = do_connection_edit (td->nmc, td->argc, td->argv);
-
- /* quit glib main loop now that we are done with this thread */
- quit ();
-
- return NULL;
-}
-
static char *
gen_func_connection_names (const char *text, int state)
{
@@ -8652,88 +8716,33 @@ nmcli_con_tab_completion (const char *text, int start, int end)
return match_array;
}
-static GArray *
-parse_preferred_connection_order (const char *order, GError **error)
-{
- char **strv, **iter;
- const char *str;
- GArray *order_arr;
- NmcSortOrder val;
- gboolean inverse, unique;
- int i;
-
- strv = nmc_strsplit_set (order, ":", -1);
- if (!strv || !*strv) {
- g_set_error (error, NMCLI_ERROR, 0,
- _("incorrect string '%s' of '--order' option"), order);
- g_strfreev (strv);
- return NULL;
- }
-
- order_arr = g_array_sized_new (FALSE, FALSE, sizeof (NmcSortOrder), 4);
- for (iter = strv; iter && *iter; iter++) {
- str = *iter;
- inverse = FALSE;
- if (str[0] == '-')
- inverse = TRUE;
- if (str[0] == '+' || str[0] == '-')
- str++;
-
- if (matches (str, "active") == 0)
- val = inverse ? NMC_SORT_ACTIVE_INV : NMC_SORT_ACTIVE;
- else if (matches (str, "name") == 0)
- val = inverse ? NMC_SORT_NAME_INV : NMC_SORT_NAME;
- else if (matches (str, "type") == 0)
- val = inverse ? NMC_SORT_TYPE_INV : NMC_SORT_TYPE;
- else if (matches (str, "path") == 0)
- val = inverse ? NMC_SORT_PATH_INV : NMC_SORT_PATH;
- else {
- g_array_unref (order_arr);
- order_arr = NULL;
- g_set_error (error, NMCLI_ERROR, 0,
- _("incorrect item '%s' in '--order' option"), *iter);
- break;
- }
- /* Check for duplicates and ignore them. */
- unique = TRUE;
- for (i = 0; i < order_arr->len; i++) {
- if (abs (g_array_index (order_arr, NmcSortOrder, i)) - abs (val) == 0) {
- unique = FALSE;
- break;
- }
- }
-
- /* Value is ok and unique, add it to the array */
- if (unique)
- g_array_append_val (order_arr, val);
- }
-
- g_strfreev (strv);
- return order_arr;
-}
+static const NMCCommand connection_cmds[] = {
+ {"show", do_connections_show, usage_connection_show },
+ {"up", do_connection_up, usage_connection_up },
+ {"down", do_connection_down, usage_connection_down },
+ {"add", do_connection_add, usage_connection_add },
+ {"edit", do_connection_edit, usage_connection_edit },
+ {"delete", do_connection_delete, usage_connection_delete },
+ {"reload", do_connection_reload, usage_connection_reload },
+ {"load", do_connection_load, usage_connection_load },
+ {"modify", do_connection_modify, usage_connection_modify },
+ {"clone", do_connection_clone, usage_connection_clone },
+ {"import", do_connection_import, usage_connection_import },
+ {"export", do_connection_export, usage_connection_export },
+ {"monitor", do_connection_monitor, usage_connection_monitor },
+ {NULL, do_connections_show, usage },
+};
/* Entry point function for connections-related commands: 'nmcli connection' */
NMCResultCode
do_connections (NmCli *nmc, int argc, char **argv)
{
- GError *error = NULL;
-
/* Register polkit agent */
nmc_start_polkit_agent_start_try (nmc);
/* Set completion function for 'nmcli con' */
rl_attempted_completion_function = (rl_completion_func_t *) nmcli_con_tab_completion;
- /* Exit early on help */
- if (nmc_arg_is_help (*argv)) {
- usage ();
- return nmc->return_value;
- }
- if (argc != 0 && nmc_arg_is_help (*(argv+1))) {
- if (usage_connection_second_level (*argv))
- return nmc->return_value;
- }
-
/* Get NMClient object early */
nmc->get_client (nmc);
@@ -8749,124 +8758,7 @@ do_connections (NmCli *nmc, int argc, char **argv)
/* Get the connection list */
nmc->connections = nm_client_get_connections (nmc->client);
- /* Now parse the command line and perform the required operation */
- if (argc == 0) {
- if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
- goto opt_error;
- nmc->return_value = do_connections_show (nmc, FALSE, FALSE, NULL, argc, argv);
- } else {
- if (matches (*argv, "show") == 0) {
- gboolean active = FALSE;
- gboolean show_secrets = FALSE;
- GArray *order = NULL;
- int i;
-
- next_arg (&argc, &argv);
- /* check connection show options [--active] [--show-secrets] */
- for (i = 0; i < 3; i++) {
- if (!active && nmc_arg_is_option (*argv, "active")) {
- active = TRUE;
- next_arg (&argc, &argv);
- }
- /* --show-secrets is deprecated in favour of global --show-secrets */
- /* Keep it here for backwards compatibility */
- if (!show_secrets && nmc_arg_is_option (*argv, "show-secrets")) {
- show_secrets = TRUE;
- next_arg (&argc, &argv);
- }
- if (!order && nmc_arg_is_option (*argv, "order")) {
- if (next_arg (&argc, &argv) != 0) {
- g_set_error_literal (&error, NMCLI_ERROR, 0,
- _("'--order' argument is missing"));
- goto opt_error;
- }
- order = parse_preferred_connection_order (*argv, &error);
- if (error)
- goto opt_error;
- next_arg (&argc, &argv);
- }
- }
- show_secrets = nmc->show_secrets || show_secrets;
- nmc->return_value = do_connections_show (nmc, active, show_secrets, order, argc, argv);
- if (order)
- g_array_unref (order);
- } else if (matches(*argv, "up") == 0) {
- nmc->return_value = do_connection_up (nmc, argc-1, argv+1);
- } else if (matches(*argv, "down") == 0) {
- nmc->return_value = do_connection_down (nmc, argc-1, argv+1);
- } 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;
- editor_thread_data.argv = argv + 1;
- editor_thread = g_thread_new ("editor-thread", connection_editor_thread_func, &editor_thread_data);
- g_thread_unref (editor_thread);
- } else if (matches(*argv, "delete") == 0) {
- nmc->return_value = do_connection_delete (nmc, argc-1, argv+1);
- } else if (matches(*argv, "reload") == 0) {
- nmc->return_value = do_connection_reload (nmc, argc-1, argv+1);
- } else if (matches(*argv, "load") == 0) {
- nmc->return_value = do_connection_load (nmc, argc-1, argv+1);
- } else if (matches (*argv, "modify") == 0) {
- gboolean temporary = FALSE;
-
- next_arg (&argc, &argv);
- if (nmc_arg_is_option (*argv, "temporary")) {
- if (nmc->complete)
- goto opt_error;
- temporary = TRUE;
- next_arg (&argc, &argv);
- }
- nmc->return_value = do_connection_modify (nmc, temporary, argc, argv);
- } else if (matches (*argv, "clone") == 0) {
- gboolean temporary = FALSE;
-
- next_arg (&argc, &argv);
- if (nmc_arg_is_option (*argv, "temporary")) {
- if (nmc->complete)
- goto opt_error;
- temporary = TRUE;
- next_arg (&argc, &argv);
- }
- nmc->return_value = do_connection_clone (nmc, temporary, argc, argv);
- } else if (matches(*argv, "import") == 0) {
- gboolean temporary = FALSE;
-
- next_arg (&argc, &argv);
- if (nmc_arg_is_option (*argv, "temporary")) {
- if (nmc->complete)
- goto opt_error;
- temporary = TRUE;
- next_arg (&argc, &argv);
- }
- nmc->return_value = do_connection_import (nmc, temporary, argc, argv);
- } else if (matches(*argv, "export") == 0) {
- nmc->return_value = do_connection_export (nmc, argc-1, argv+1);
- } 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;
- }
- }
-
- return nmc->return_value;
-
-opt_error:
- 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;
+ return nmc_do_cmd (nmc, connection_cmds, *argv, argc, argv);
}
void
diff --git a/clients/cli/connections.h b/clients/cli/connections.h
index cb70a3d52e..c73178e24e 100644
--- a/clients/cli/connections.h
+++ b/clients/cli/connections.h
@@ -35,4 +35,10 @@ nmc_read_connection_properties (NmCli *nmc,
void nmc_active_connection_state_to_color (NMActiveConnectionState state, NmcTermColor *color);
+extern NmcOutputField nmc_fields_con_show[];
+extern NmcOutputField nmc_fields_settings_names[];
+extern NmcOutputField nmc_fields_con_active_details_general[];
+extern NmcOutputField nmc_fields_con_active_details_vpn[];
+extern NmcOutputField nmc_fields_con_active_details_groups[];
+
#endif /* NMC_CONNECTIONS_H */
diff --git a/clients/cli/devices.c b/clients/cli/devices.c
index 7b043fd9ba..afa769f63c 100644
--- a/clients/cli/devices.c
+++ b/clients/cli/devices.c
@@ -37,7 +37,7 @@
#define PROMPT_INTERFACES _("Interface(s): ")
/* Available fields for 'device status' */
-static NmcOutputField nmc_fields_dev_status[] = {
+NmcOutputField nmc_fields_dev_status[] = {
{"DEVICE", N_("DEVICE")}, /* 0 */
{"TYPE", N_("TYPE")}, /* 1 */
{"STATE", N_("STATE")}, /* 2 */
@@ -52,7 +52,7 @@ static NmcOutputField nmc_fields_dev_status[] = {
/* Available fields for 'device show' - GENERAL part */
-static NmcOutputField nmc_fields_dev_show_general[] = {
+NmcOutputField nmc_fields_dev_show_general[] = {
{"NAME", N_("NAME")}, /* 0 */
{"DEVICE", N_("DEVICE")}, /* 1 */
{"TYPE", N_("TYPE")}, /* 2 */
@@ -86,7 +86,7 @@ static NmcOutputField nmc_fields_dev_show_general[] = {
#define NMC_FIELDS_DEV_SHOW_GENERAL_COMMON "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,HWADDR,STATE"
/* Available fields for 'device show' - CONNECTIONS part */
-static NmcOutputField nmc_fields_dev_show_connections[] = {
+NmcOutputField nmc_fields_dev_show_connections[] = {
{"NAME", N_("NAME")}, /* 0 */
{"AVAILABLE-CONNECTION-PATHS", N_("AVAILABLE-CONNECTION-PATHS")}, /* 1 */
{"AVAILABLE-CONNECTIONS", N_("AVAILABLE-CONNECTIONS")}, /* 2 */
@@ -96,7 +96,7 @@ static NmcOutputField nmc_fields_dev_show_connections[] = {
#define NMC_FIELDS_DEV_SHOW_CONNECTIONS_COMMON "AVAILABLE-CONNECTION-PATHS,AVAILABLE-CONNECTIONS"
/* Available fields for 'device show' - CAPABILITIES part */
-static NmcOutputField nmc_fields_dev_show_cap[] = {
+NmcOutputField nmc_fields_dev_show_cap[] = {
{"NAME", N_("NAME")}, /* 0 */
{"CARRIER-DETECT", N_("CARRIER-DETECT")}, /* 1 */
{"SPEED", N_("SPEED")}, /* 2 */
@@ -107,7 +107,7 @@ static NmcOutputField nmc_fields_dev_show_cap[] = {
#define NMC_FIELDS_DEV_SHOW_CAP_COMMON "NAME,CARRIER-DETECT,SPEED,IS-SOFTWARE"
/* Available fields for 'device show' - wired properties part */
-static NmcOutputField nmc_fields_dev_show_wired_prop[] = {
+NmcOutputField nmc_fields_dev_show_wired_prop[] = {
{"NAME", N_("NAME")}, /* 0 */
{"CARRIER", N_("CARRIER")}, /* 1 */
{"S390-SUBCHANNELS", N_("S390-SUBCHANNELS")}, /* 2 */
@@ -117,7 +117,7 @@ static NmcOutputField nmc_fields_dev_show_wired_prop[] = {
#define NMC_FIELDS_DEV_SHOW_WIRED_PROP_COMMON "NAME,CARRIER,S390-SUBCHANNELS"
/* Available fields for 'device show' - wireless properties part */
-static NmcOutputField nmc_fields_dev_show_wifi_prop[] = {
+NmcOutputField nmc_fields_dev_show_wifi_prop[] = {
{"NAME", N_("NAME")}, /* 0 */
{"WEP", N_("WEP")}, /* 1 */
{"WPA", N_("WPA")}, /* 2 */
@@ -134,7 +134,7 @@ static NmcOutputField nmc_fields_dev_show_wifi_prop[] = {
#define NMC_FIELDS_DEV_SHOW_WIFI_PROP_COMMON "NAME,WEP,WPA,WPA2,TKIP,CCMP,AP,ADHOC"
/* Available fields for 'device show' - wimax properties part */
-static NmcOutputField nmc_fields_dev_show_wimax_prop[] = {
+NmcOutputField nmc_fields_dev_show_wimax_prop[] = {
{"NAME", N_("NAME")}, /* 0 */
{"CTR-FREQ", N_("CTR-FREQ")}, /* 1 */
{"RSSI", N_("RSSI")}, /* 2 */
@@ -147,7 +147,7 @@ static NmcOutputField nmc_fields_dev_show_wimax_prop[] = {
#define NMC_FIELDS_DEV_SHOW_WIMAX_PROP_COMMON "NAME,CTR-FREQ,RSSI,CINR,TX-POW,BSID"
/* Available fields for 'device wifi list' */
-static NmcOutputField nmc_fields_dev_wifi_list[] = {
+NmcOutputField nmc_fields_dev_wifi_list[] = {
{"NAME", N_("NAME")}, /* 0 */
{"SSID", N_("SSID")}, /* 1 */
{"SSID-HEX", N_("SSID-HEX")}, /* 2 */
@@ -173,7 +173,7 @@ static NmcOutputField nmc_fields_dev_wifi_list[] = {
#define NMC_FIELDS_DEV_WIFI_LIST_FOR_DEV_LIST "NAME,"NMC_FIELDS_DEV_WIFI_LIST_COMMON
/* Available fields for 'device wimax list' */
-static NmcOutputField nmc_fields_dev_wimax_list[] = {
+NmcOutputField nmc_fields_dev_wimax_list[] = {
{"NAME", N_("NAME")}, /* 0 */
{"NSP", N_("NSP")}, /* 1 */
{"SIGNAL", N_("SIGNAL")}, /* 2 */
@@ -188,7 +188,7 @@ static NmcOutputField nmc_fields_dev_wimax_list[] = {
#define NMC_FIELDS_DEV_WIMAX_LIST_FOR_DEV_LIST "NAME,"NMC_FIELDS_DEV_WIMAX_LIST_COMMON
/* Available fields for 'device show' - BOND, BRIDGE part */
-static NmcOutputField nmc_fields_dev_show_master_prop[] = {
+NmcOutputField nmc_fields_dev_show_master_prop[] = {
{"NAME", N_("NAME")}, /* 0 */
{"SLAVES", N_("SLAVES")}, /* 1 */
{NULL, NULL}
@@ -197,7 +197,7 @@ static NmcOutputField nmc_fields_dev_show_master_prop[] = {
#define NMC_FIELDS_DEV_SHOW_MASTER_PROP_COMMON "NAME,SLAVES"
/* Available fields for 'device show' - TEAM part */
-static NmcOutputField nmc_fields_dev_show_team_prop[] = {
+NmcOutputField nmc_fields_dev_show_team_prop[] = {
{"NAME", N_("NAME")}, /* 0 */
{"SLAVES", N_("SLAVES")}, /* 1 */
{"CONFIG", N_("CONFIG")}, /* 2 */
@@ -207,7 +207,7 @@ static NmcOutputField nmc_fields_dev_show_team_prop[] = {
#define NMC_FIELDS_DEV_SHOW_TEAM_PROP_COMMON "NAME,SLAVES,CONFIG"
/* Available fields for 'device show' - VLAN part */
-static NmcOutputField nmc_fields_dev_show_vlan_prop[] = {
+NmcOutputField nmc_fields_dev_show_vlan_prop[] = {
{"NAME", N_("NAME")}, /* 0 */
{"PARENT", N_("PARENT")}, /* 1 */
{"ID", N_("ID")}, /* 2 */
@@ -217,7 +217,7 @@ static NmcOutputField nmc_fields_dev_show_vlan_prop[] = {
#define NMC_FIELDS_DEV_SHOW_VLAN_PROP_COMMON "NAME,PARENT,ID"
/* Available fields for 'device show' - BLUETOOTH part */
-static NmcOutputField nmc_fields_dev_show_bluetooth[] = {
+NmcOutputField nmc_fields_dev_show_bluetooth[] = {
{"NAME", N_("NAME")}, /* 0 */
{"CAPABILITIES", N_("CAPABILITIES")}, /* 1 */
{NULL, NULL}
@@ -232,7 +232,7 @@ extern NmcOutputField nmc_fields_dhcp4_config[];
extern NmcOutputField nmc_fields_dhcp6_config[];
/* Available sections for 'device show' */
-static NmcOutputField nmc_fields_dev_show_sections[] = {
+NmcOutputField nmc_fields_dev_show_sections[] = {
{"GENERAL", N_("GENERAL"), 0, nmc_fields_dev_show_general + 1 }, /* 0 */
{"CAPABILITIES", N_("CAPABILITIES"), 0, nmc_fields_dev_show_cap + 1 }, /* 1 */
{"WIFI-PROPERTIES", N_("WIFI-PROPERTIES"), 0, nmc_fields_dev_show_wifi_prop + 1 }, /* 2 */
@@ -258,7 +258,7 @@ static NmcOutputField nmc_fields_dev_show_sections[] = {
"GENERAL.CONNECTION,GENERAL.CON-PATH,WIRED-PROPERTIES,IP4,IP6"
/* Available fields for 'device lldp' */
-static NmcOutputField nmc_fields_dev_lldp_list[] = {
+NmcOutputField nmc_fields_dev_lldp_list[] = {
{"NAME", N_("NAME")}, /* 0 */
{"DEVICE", N_("DEVICE")}, /* 1 */
{"CHASSIS-ID", N_("CHASSIS-ID")}, /* 2 */
@@ -538,18 +538,30 @@ nmc_get_devices_sorted (NMClient *client)
}
static void
-complete_device (NMDevice **devices, const char *prefix)
+complete_device (NMDevice **devices, const char *prefix, gboolean wifi_only)
{
int i;
for (i = 0; devices[i]; i++) {
const char *iface = nm_device_get_iface (devices[i]);
+ if (wifi_only && !NM_IS_DEVICE_WIFI (devices[i]))
+ continue;
+
if (g_str_has_prefix (iface, prefix))
g_print ("%s\n", iface);
}
}
+void
+nmc_complete_device (NMClient *client, const char *prefix, gboolean wifi_only)
+{
+ gs_free NMDevice **devices = NULL;
+
+ devices = nmc_get_devices_sorted (client);
+ complete_device (devices, prefix, wifi_only);
+}
+
static GSList *
get_device_list (NmCli *nmc, int argc, char **argv)
{
@@ -578,7 +590,7 @@ get_device_list (NmCli *nmc, int argc, char **argv)
devices = nmc_get_devices_sorted (nmc->client);
while (arg_num > 0) {
if (arg_num == 1 && nmc->complete)
- complete_device (devices, *arg_ptr);
+ complete_device (devices, *arg_ptr, FALSE);
device = NULL;
for (i = 0; devices[i]; i++) {
@@ -640,7 +652,7 @@ get_device (NmCli *nmc, int *argc, char ***argv, GError **error)
}
if (nmc->complete && !*argc)
- complete_device (devices, ifname);
+ complete_device (devices, ifname, FALSE);
if (devices[i] == NULL) {
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_NOT_FOUND,
@@ -2484,6 +2496,118 @@ show_access_point_info (NMDevice *device, NmCli *nmc)
g_free (info);
}
+/*
+ * Find a Wi-Fi device with 'iface' in 'devices' array. If 'iface' is NULL,
+ * the first Wi-Fi device is returned. 'idx' parameter is updated to the point
+ * where the function finished so that the function can be called repeatedly
+ * to get next matching device.
+ * Returns: found device or NULL
+ */
+static NMDevice *
+find_wifi_device_by_iface (NMDevice **devices, const char *iface, int *idx)
+{
+ int i;
+
+ for (i = idx ? *idx : 0; devices[i]; i++) {
+ const char *dev_iface = nm_device_get_iface (devices[i]);
+
+ if (!NM_IS_DEVICE_WIFI (devices[i]))
+ continue;
+
+ if (iface) {
+ /* If a iface was specified then use it. */
+ if (g_strcmp0 (dev_iface, iface) == 0)
+ break;
+ } else {
+ /* Else return the first Wi-Fi device. */
+ break;
+ }
+ }
+
+ if (idx)
+ *idx = i + 1;
+ return devices[i];
+}
+
+/*
+ * Find AP on 'device' according to 'bssid' or 'ssid' parameter.
+ * Returns: found AP or NULL
+ */
+static NMAccessPoint *
+find_ap_on_device (NMDevice *device, const char *bssid, const char *ssid, gboolean complete)
+{
+ const GPtrArray *aps;
+ NMAccessPoint *ap = NULL;
+ int i;
+
+ g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
+
+ aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device));
+ for (i = 0; i < aps->len; i++) {
+ NMAccessPoint *candidate_ap = g_ptr_array_index (aps, i);
+
+ if (bssid) {
+ /* Parameter is BSSID */
+ const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap);
+
+ /* Compare BSSIDs */
+ if (complete) {
+ if (g_str_has_prefix (candidate_bssid, bssid))
+ g_print ("%s\n", candidate_bssid);
+ } else if (strcmp (bssid, candidate_bssid) == 0) {
+ ap = candidate_ap;
+ break;
+ }
+ }
+
+ if (ssid) {
+ /* Parameter is SSID */
+ GBytes *candidate_ssid;
+ char *ssid_tmp;
+
+ candidate_ssid = nm_access_point_get_ssid (candidate_ap);
+ if (!candidate_ssid)
+ continue;
+
+ ssid_tmp = nm_utils_ssid_to_utf8 (g_bytes_get_data (candidate_ssid, NULL),
+ g_bytes_get_size (candidate_ssid));
+
+ /* Compare SSIDs */
+ if (complete) {
+ if (g_str_has_prefix (ssid_tmp, ssid))
+ g_print ("%s\n", ssid_tmp);
+ } else if (strcmp (ssid, ssid_tmp) == 0) {
+ ap = candidate_ap;
+ g_free (ssid_tmp);
+ break;
+ }
+ g_free (ssid_tmp);
+ }
+ }
+
+ return ap;
+}
+
+static void
+complete_aps (NMDevice **devices, const char *ifname,
+ const char *bssid_prefix, const char *ssid_prefix)
+{
+ int devices_idx = 0;
+ NMDevice *device;
+
+ while ((device = find_wifi_device_by_iface (devices, ifname, &devices_idx)))
+ find_ap_on_device (device, bssid_prefix, ssid_prefix, TRUE);
+}
+
+void
+nmc_complete_bssid (NMClient *client, const char *ifname, const char *bssid_prefix)
+{
+ gs_free NMDevice **devices = NULL;
+
+ devices = nmc_get_devices_sorted (client);
+ complete_aps (devices, ifname, bssid_prefix, NULL);
+}
+
static NMCResultCode
do_device_wifi_list (NmCli *nmc, int argc, char **argv)
{
@@ -2492,7 +2616,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
NMAccessPoint *ap = NULL;
const char *ifname = NULL;
const char *bssid_user = NULL;
- NMDevice **devices = NULL;
+ gs_free NMDevice **devices = NULL;
const GPtrArray *aps;
APInfo *info;
int i, j;
@@ -2503,27 +2627,29 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
size_t tmpl_len;
const char *base_hdr = _("Wi-Fi scan list");
- /* Not (yet?) supported */
- if (nmc->complete)
- return nmc->return_value;
+ devices = nmc_get_devices_sorted (nmc->client);
while (argc > 0) {
+ if (argc == 1 && nmc->complete)
+ nmc_complete_strings (*argv, "ifname", "bssid", NULL);
+
if (strcmp (*argv, "ifname") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
ifname = *argv;
+ complete_device (devices, ifname, TRUE);
} else if (strcmp (*argv, "bssid") == 0 || strcmp (*argv, "hwaddr") == 0) {
/* hwaddr is deprecated and will be removed later */
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
bssid_user = *argv;
- } else {
+ if (argc == 1 && nmc->complete)
+ complete_aps (devices, NULL, bssid_user, NULL);
+ } else if (!nmc->complete) {
g_printerr (_("Unknown parameter: %s\n"), *argv);
}
@@ -2545,28 +2671,18 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
if (error) {
g_string_printf (nmc->return_text, _("Error: 'device wifi': %s"), error->message);
g_error_free (error);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
- devices = nmc_get_devices_sorted (nmc->client);
- if (ifname) {
- /* Device specified - list only APs of this interface */
- for (i = 0; devices[i]; i++) {
- NMDevice *candidate = devices[i];
- const char *dev_iface = nm_device_get_iface (candidate);
+ if (nmc->complete)
+ return nmc->return_value;
- if (!g_strcmp0 (dev_iface, ifname)) {
- device = candidate;
- break;
- }
- }
+ if (ifname) {
+ device = find_wifi_device_by_iface (devices, ifname, NULL);
if (!device) {
g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
- nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
- goto error;
+ return NMC_RESULT_ERROR_NOT_FOUND;
}
-
/* Main header name */
nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, ifname);
@@ -2587,8 +2703,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
if (!ap) {
g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."),
bssid_user);
- nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
- goto error;
+ return NMC_RESULT_ERROR_NOT_FOUND;
}
/* Add headers (field names) */
arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
@@ -2619,8 +2734,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
_("Error: Device '%s' is not a Wi-Fi device."),
ifname);
}
- nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
- goto error;
+ return NMC_RESULT_ERROR_UNKNOWN;
}
} else {
gboolean empty_line = FALSE;
@@ -2671,8 +2785,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
if (!ap) {
g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."),
bssid_user);
- nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
- goto error;
+ return NMC_RESULT_ERROR_NOT_FOUND;
}
} else {
for (i = 0; devices[i]; i++) {
@@ -2693,101 +2806,9 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
}
}
-error:
- g_free (devices);
return nmc->return_value;
}
-/*
- * Find a Wi-Fi device with 'iface' in 'devices' array. If 'iface' is NULL,
- * the first Wi-Fi device is returned. 'idx' parameter is updated to the point
- * where the function finished so that the function can be called repeatedly
- * to get next matching device.
- * Returns: found device or NULL
- */
-static NMDevice *
-find_wifi_device_by_iface (const GPtrArray *devices, const char *iface, int *idx)
-{
- NMDevice *device = NULL;
- int i;
-
- for (i = *idx; i < devices->len; i++) {
- NMDevice *candidate = g_ptr_array_index (devices, i);
- const char *dev_iface = nm_device_get_iface (candidate);
-
- if (!NM_IS_DEVICE_WIFI (candidate))
- continue;
-
- if (iface) {
- /* If a iface was specified then use it. */
- if (g_strcmp0 (dev_iface, iface) == 0) {
- device = candidate;
- break;
- }
- } else {
- /* Else return the first Wi-Fi device. */
- device = candidate;
- break;
- }
- }
-
- *idx = i + 1;
- return device;
-}
-
-/*
- * Find AP on 'device' according to 'bssid' or 'ssid' parameter.
- * Returns: found AP or NULL
- */
-static NMAccessPoint *
-find_ap_on_device (NMDevice *device, GByteArray *bssid, const char *ssid)
-{
- const GPtrArray *aps;
- NMAccessPoint *ap = NULL;
- int i;
-
- g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
- g_return_val_if_fail ((bssid && !ssid) || (!bssid && ssid), NULL);
-
- aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device));
- for (i = 0; i < aps->len; i++) {
- NMAccessPoint *candidate_ap = g_ptr_array_index (aps, i);
-
- if (ssid) {
- /* Parameter is SSID */
- GBytes *candidate_ssid;
-
- candidate_ssid = nm_access_point_get_ssid (candidate_ap);
- if (candidate_ssid) {
- char *ssid_tmp = nm_utils_ssid_to_utf8 (g_bytes_get_data (candidate_ssid, NULL),
- g_bytes_get_size (candidate_ssid));
-
- /* Compare SSIDs */
- if (strcmp (ssid, ssid_tmp) == 0) {
- ap = candidate_ap;
- g_free (ssid_tmp);
- break;
- }
- g_free (ssid_tmp);
- }
- } else if (bssid) {
- /* Parameter is BSSID */
- const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap);
- char *bssid_up = nm_utils_hwaddr_ntoa (bssid->data, bssid->len);
-
- /* Compare BSSIDs */
- if (strcmp (bssid_up, candidate_bssid) == 0) {
- ap = candidate_ap;
- g_free (bssid_up);
- break;
- }
- g_free (bssid_up);
- }
- }
-
- return ap;
-}
-
static NMCResultCode
do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
{
@@ -2811,27 +2832,31 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
gboolean wep_passphrase = FALSE;
GByteArray *bssid1_arr = NULL;
GByteArray *bssid2_arr = NULL;
- const GPtrArray *devices;
+ gs_free NMDevice **devices = NULL;
int devices_idx;
char *ssid_ask = NULL;
char *passwd_ask = NULL;
- /* Not (yet?) supported */
- if (nmc->complete)
- return nmc->return_value;
-
/* Set default timeout waiting for operation completion. */
if (nmc->timeout == -1)
nmc->timeout = 90;
+ devices = nmc_get_devices_sorted (nmc->client);
+
/* Get the first compulsory argument (SSID or BSSID) */
if (argc > 0) {
param_user = *argv;
bssid1_arr = nm_utils_hwaddr_atoba (param_user, ETH_ALEN);
+ if (argc == 1 && nmc->complete)
+ complete_aps (devices, NULL, param_user, param_user);
+
argc--;
argv++;
} else {
+ /* nmc_do_cmd() should not call this with argc=0. */
+ g_assert (!nmc->complete);
+
if (nmc->ask) {
ssid_ask = nmc_readline (_("SSID or BSSID: "));
param_user = ssid_ask ? ssid_ask : "";
@@ -2840,46 +2865,56 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
if (!ssid_ask) {
g_string_printf (nmc->return_text, _("Error: SSID or BSSID are missing."));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
}
/* Get the rest of the parameters */
while (argc > 0) {
+ if (argc == 1 && nmc->complete) {
+ nmc_complete_strings (*argv, "ifname", "bssid", "password", "wep-key-type",
+ "name", "private", "hidden", NULL);
+ }
+
if (strcmp (*argv, "ifname") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
ifname = *argv;
+ complete_device (devices, ifname, TRUE);
} else if (strcmp (*argv, "bssid") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
bssid = *argv;
+ if (argc == 1 && nmc->complete)
+ complete_aps (devices, NULL, bssid, NULL);
bssid2_arr = nm_utils_hwaddr_atoba (bssid, ETH_ALEN);
if (!bssid2_arr) {
g_string_printf (nmc->return_text, _("Error: bssid argument value '%s' is not a valid BSSID."),
bssid);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
} else if (strcmp (*argv, "password") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
password = *argv;
} else if (strcmp (*argv, "wep-key-type") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
+ if (argc == 1 && nmc->complete)
+ nmc_complete_strings (*argv, "key", "phrase", NULL);
if (strcmp (*argv, "key") == 0)
wep_passphrase = FALSE;
else if (strcmp (*argv, "phrase") == 0)
@@ -2889,13 +2924,13 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
_("Error: wep-key-type argument value '%s' is invalid, use 'key' or 'phrase'."),
*argv);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
} else if (strcmp (*argv, "name") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
con_name = *argv;
} else if (strcmp (*argv, "private") == 0) {
@@ -2903,28 +2938,32 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
+ if (argc == 1 && nmc->complete)
+ nmc_complete_bool (*argv);
if (!nmc_string_to_bool (*argv, &private, &err_tmp)) {
g_string_printf (nmc->return_text, _("Error: %s: %s."), *(argv-1), err_tmp->message);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
g_clear_error (&err_tmp);
- goto error;
+ goto finish;
}
} else if (strcmp (*argv, "hidden") == 0) {
GError *err_tmp = NULL;
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
+ if (argc == 1 && nmc->complete)
+ nmc_complete_bool (*argv);
if (!nmc_string_to_bool (*argv, &hidden, &err_tmp)) {
g_string_printf (nmc->return_text, _("Error: %s: %s."), *(argv-1), err_tmp->message);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
g_clear_error (&err_tmp);
- goto error;
+ goto finish;
}
- } else {
+ } else if (!nmc->complete) {
g_printerr (_("Unknown parameter: %s\n"), *argv);
}
@@ -2932,21 +2971,22 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
argv++;
}
+ if (nmc->complete)
+ goto finish;
+
/* Verify SSID/BSSID parameters */
if (bssid1_arr && bssid2_arr && memcmp (bssid1_arr->data, bssid2_arr->data, ETH_ALEN)) {
g_string_printf (nmc->return_text, _("Error: BSSID to connect to (%s) differs from bssid argument (%s)."),
param_user, bssid);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
if (!bssid1_arr && strlen (param_user) > 32) {
g_string_printf (nmc->return_text, _("Error: Parameter '%s' is neither SSID nor BSSID."), param_user);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
- devices = nm_client_get_devices (nmc->client);
-
/* Find a device to activate the connection on */
devices_idx = 0;
device = find_wifi_device_by_iface (devices, ifname, &devices_idx);
@@ -2957,7 +2997,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
else
g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found."));
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
- goto error;
+ goto finish;
}
/* For hidden SSID first scan it so that NM learns about the AP */
@@ -2979,18 +3019,20 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
scan_err->message);
g_clear_error (&scan_err);
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
- goto error;
+ goto finish;
}
}
/* Find an AP to connect to */
- ap = find_ap_on_device (device, bssid1_arr, bssid1_arr ? NULL : param_user);
+ ap = find_ap_on_device (device, bssid1_arr ? param_user : NULL,
+ bssid1_arr ? NULL : param_user, FALSE);
if (!ap && !ifname) {
NMDevice *dev;
/* AP not found, ifname was not specified, so try finding the AP on another device. */
while ((dev = find_wifi_device_by_iface (devices, NULL, &devices_idx)) != NULL) {
- ap = find_ap_on_device (dev, bssid1_arr, bssid1_arr ? NULL : param_user);
+ ap = find_ap_on_device (dev, bssid1_arr ? param_user : NULL,
+ bssid1_arr ? NULL : param_user, FALSE);
if (ap) {
device = dev;
break;
@@ -3004,7 +3046,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
else
g_string_printf (nmc->return_text, _("Error: No access point with BSSID '%s' found."), param_user);
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
- goto error;
+ goto finish;
}
/* If there are some connection data from user, create a connection and
@@ -3107,7 +3149,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
add_and_activate_cb,
info);
-error:
+finish:
if (bssid1_arr)
g_byte_array_free (bssid1_arr, TRUE);
if (bssid2_arr)
@@ -3260,8 +3302,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
const char *password = NULL;
gboolean show_password = FALSE;
NMDevice *device = NULL;
- int devices_idx;
- const GPtrArray *devices;
+ gs_free NMDevice **devices = NULL;
NMDeviceWifiCapabilities caps;
NMConnection *connection = NULL;
NMSettingConnection *s_con;
@@ -3271,66 +3312,65 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
GBytes *ssid_bytes;
GError *error = NULL;
- /* Not (yet?) supported */
- if (nmc->complete)
- return nmc->return_value;
-
/* Set default timeout waiting for operation completion. */
if (nmc->timeout == -1)
nmc->timeout = 60;
+ devices = nmc_get_devices_sorted (nmc->client);
+
while (argc > 0) {
+ if (argc == 1 && nmc->complete) {
+ nmc_complete_strings (*argv, "ifname", "con-name", "ssid", "band",
+ "channel", "password", NULL);
+ }
+
if (strcmp (*argv, "ifname") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
ifname = *argv;
+ if (argc == 1 && nmc->complete)
+ complete_device (devices, ifname, TRUE);
} else if (strcmp (*argv, "con-name") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
con_name = *argv;
} else if (strcmp (*argv, "ssid") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
ssid = *argv;
if (strlen (ssid) > 32) {
g_string_printf (nmc->return_text, _("Error: ssid is too long."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
} else if (strcmp (*argv, "band") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
band = *argv;
+ if (argc == 1 && nmc->complete)
+ nmc_complete_strings (band, "a", "bg", NULL);
if (strcmp (band, "a") && strcmp (band, "bg")) {
g_string_printf (nmc->return_text, _("Error: band argument value '%s' is invalid; use 'a' or 'bg'."),
band);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
} else if (strcmp (*argv, "channel") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
channel = *argv;
} else if (strcmp (*argv, "password") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
password = *argv;
/* --show-password is deprecated in favour of global --show-secrets option */
@@ -3339,8 +3379,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
show_password = TRUE;
} else {
g_string_printf (nmc->return_text, _("Error: Unknown parameter %s."), *argv);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
argc--;
@@ -3348,6 +3387,9 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
}
show_password = nmc->show_secrets || show_password;
+ if (nmc->complete)
+ return nmc->return_value;
+
/* Verify band and channel parameters */
if (!channel) {
if (g_strcmp0 (band, "bg") == 0)
@@ -3358,30 +3400,25 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
if (channel) {
if (!band) {
g_string_printf (nmc->return_text, _("Error: channel requires band too."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
if ( !nmc_string_to_uint (channel, TRUE, 1, 5825, &channel_int)
|| !nm_utils_wifi_is_channel_valid (channel_int, band)) {
g_string_printf (nmc->return_text, _("Error: channel '%s' not valid for band '%s'."),
channel, band);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
}
/* Find Wi-Fi device. When no ifname is provided, the first Wi-Fi is used. */
- devices = nm_client_get_devices (nmc->client);
- devices_idx = 0;
- device = find_wifi_device_by_iface (devices, ifname, &devices_idx);
+ device = find_wifi_device_by_iface (devices, ifname, NULL);
if (!device) {
if (ifname)
g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), ifname);
else
g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found."));
- nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
- goto error;
+ return NMC_RESULT_ERROR_UNKNOWN;
}
/* Check device supported mode */
@@ -3393,8 +3430,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
else {
g_string_printf (nmc->return_text, _("Error: Device '%s' supports neither AP nor Ad-Hoc mode."),
nm_device_get_iface (device));
- nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
- goto error;
+ return NMC_RESULT_ERROR_UNKNOWN;
}
/* Create a connection with appropriate parameters */
@@ -3427,9 +3463,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
if (!set_wireless_security_for_hotspot (s_wsec, wifi_mode, caps, password, show_password, &error)) {
g_object_unref (connection);
g_string_printf (nmc->return_text, _("Error: Invalid 'password': %s."), error->message);
- nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
g_clear_error (&error);
- goto error;
+ return NMC_RESULT_ERROR_UNKNOWN;
}
s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
@@ -3457,7 +3492,6 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
add_and_activate_cb,
info);
-error:
return nmc->return_value;
}
@@ -3482,51 +3516,53 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
NMDevice *device;
const char *ifname = NULL;
GPtrArray *ssids;
- const GPtrArray *devices;
- int devices_idx;
+ gs_free NMDevice **devices = NULL;
GVariantBuilder builder, array_builder;
GVariant *options;
const char *ssid;
int i;
- /* Not (yet?) supported */
- if (nmc->complete)
- return nmc->return_value;
-
ssids = g_ptr_array_new ();
+ devices = nmc_get_devices_sorted (nmc->client);
/* Get the parameters */
while (argc > 0) {
+ if (argc == 1 && nmc->complete)
+ nmc_complete_strings (*argv, "ifname", "ssid", NULL);
+
if (strcmp (*argv, "ifname") == 0) {
if (ifname) {
g_string_printf (nmc->return_text, _("Error: '%s' cannot repeat."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
ifname = *argv;
+ if (argc == 1 && nmc->complete)
+ complete_device (devices, ifname, TRUE);
} else if (strcmp (*argv, "ssid") == 0) {
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto error;
+ goto finish;
}
g_ptr_array_add (ssids, *argv);
- } else
+ } else if (!nmc->complete)
g_printerr (_("Unknown parameter: %s\n"), *argv);
argc--;
argv++;
}
+ if (nmc->complete)
+ goto finish;
+
/* Find Wi-Fi device to scan on. When no ifname is provided, the first Wi-Fi is used. */
- devices = nm_client_get_devices (nmc->client);
- devices_idx = 0;
- device = find_wifi_device_by_iface (devices, ifname, &devices_idx);
+ device = find_wifi_device_by_iface (devices, ifname, NULL);
if (!device) {
if (ifname)
@@ -3534,7 +3570,7 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
else
g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found."));
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
- goto error;
+ goto finish;
}
@@ -3557,10 +3593,8 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
nm_device_wifi_request_scan_async (NM_DEVICE_WIFI (device),
NULL, request_rescan_cb, nmc);
- g_ptr_array_free (ssids, FALSE);
- return nmc->return_value;
-error:
nmc->should_wait++;
+finish:
g_ptr_array_free (ssids, FALSE);
return nmc->return_value;
}
diff --git a/clients/cli/devices.h b/clients/cli/devices.h
index 01ff4819ea..672944beda 100644
--- a/clients/cli/devices.h
+++ b/clients/cli/devices.h
@@ -24,10 +24,30 @@
NMCResultCode do_devices (NmCli *nmc, int argc, char **argv);
+void nmc_complete_device (NMClient *client, const char *prefix, gboolean wifi_only);
+
+void nmc_complete_bssid (NMClient *client, const char *ifname, const char *bssid_prefix);
+
void monitor_devices (NmCli *nmc);
NMDevice ** nmc_get_devices_sorted (NMClient *client);
void nmc_device_state_to_color (NMDeviceState state, NmcTermColor *color, NmcTermFormat *color_fmt);
+extern NmcOutputField nmc_fields_dev_status[];
+extern NmcOutputField nmc_fields_dev_show_general[];
+extern NmcOutputField nmc_fields_dev_show_connections[];
+extern NmcOutputField nmc_fields_dev_show_cap[];
+extern NmcOutputField nmc_fields_dev_show_wired_prop[];
+extern NmcOutputField nmc_fields_dev_show_wifi_prop[];
+extern NmcOutputField nmc_fields_dev_show_wimax_prop[];
+extern NmcOutputField nmc_fields_dev_wifi_list[];
+extern NmcOutputField nmc_fields_dev_wimax_list[];
+extern NmcOutputField nmc_fields_dev_show_master_prop[];
+extern NmcOutputField nmc_fields_dev_show_team_prop[];
+extern NmcOutputField nmc_fields_dev_show_vlan_prop[];
+extern NmcOutputField nmc_fields_dev_show_bluetooth[];
+extern NmcOutputField nmc_fields_dev_show_sections[];
+extern NmcOutputField nmc_fields_dev_lldp_list[];
+
#endif /* NMC_DEVICES_H */
diff --git a/clients/cli/general.c b/clients/cli/general.c
index 739cdf8536..b919ccb549 100644
--- a/clients/cli/general.c
+++ b/clients/cli/general.c
@@ -24,6 +24,7 @@
#include "polkit-agent.h"
#include "utils.h"
+#include "common.h"
#include "general.h"
#include "common.h"
#include "nm-common-macros.h"
@@ -389,6 +390,23 @@ show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_fl
return TRUE;
}
+static NMCResultCode
+do_general_status (NmCli *nmc, int argc, char **argv)
+{
+ gs_free_error GError *error = NULL;
+
+ if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
+ g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+ return NMC_RESULT_ERROR_USER_INPUT;
+ }
+
+ if (nmc->complete)
+ return nmc->return_value;
+
+ show_nm_status (nmc, NULL, NULL);
+ return nmc->return_value;
+}
+
static const char *
permission_to_string (NMClientPermission perm)
{
@@ -493,6 +511,23 @@ show_nm_permissions (NmCli *nmc)
return TRUE;
}
+static NMCResultCode
+do_general_permissions (NmCli *nmc, int argc, char **argv)
+{
+ gs_free_error GError *error = NULL;
+
+ if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
+ g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+ return NMC_RESULT_ERROR_USER_INPUT;
+ }
+
+ if (nmc->complete)
+ return nmc->return_value;
+
+ show_nm_permissions (nmc);
+ return nmc->return_value;
+}
+
static gboolean
show_general_logging (NmCli *nmc)
{
@@ -546,6 +581,51 @@ show_general_logging (NmCli *nmc)
return TRUE;
}
+static NMCResultCode
+do_general_logging (NmCli *nmc, int argc, char **argv)
+{
+ gs_free_error GError *error = NULL;
+
+ if (argc == 0) {
+ if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
+ g_string_printf (nmc->return_text, _("Error: %s."), error->message);
+ g_error_free (error);
+ return NMC_RESULT_ERROR_USER_INPUT;
+ }
+
+ if (nmc->complete)
+ return nmc->return_value;
+
+ show_general_logging (nmc);
+ } else {
+ /* arguments provided -> set logging level and domains */
+ const char *level = NULL;
+ const char *domains = NULL;
+ nmc_arg_t exp_args[] = { {"level", TRUE, &level, TRUE},
+ {"domains", TRUE, &domains, TRUE},
+ {NULL} };
+
+ /* TODO: nmc_parse_args needs completion */
+ if (nmc->complete)
+ return nmc->return_value;
+
+ if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, &error)) {
+ g_string_assign (nmc->return_text, error->message);
+ return error->code;
+ }
+
+ nmc->get_client (nmc); /* create NMClient */
+ nm_client_set_logging (nmc->client, level, domains, &error);
+ if (error) {
+ g_string_printf (nmc->return_text, _("Error: failed to set logging: %s"),
+ error->message);
+ return NMC_RESULT_ERROR_UNKNOWN;
+ }
+ }
+
+ return nmc->return_value;
+}
+
static void
save_hostname_cb (GObject *object, GAsyncResult *result, gpointer user_data)
{
@@ -562,129 +642,55 @@ save_hostname_cb (GObject *object, GAsyncResult *result, gpointer user_data)
quit ();
}
-/*
- * Entry point function for general operations 'nmcli general'
- */
-NMCResultCode
-do_general (NmCli *nmc, int argc, char **argv)
+static NMCResultCode
+do_general_hostname (NmCli *nmc, int argc, char **argv)
{
- GError *error = NULL;
-
- /* Register polkit agent */
- nmc_start_polkit_agent_start_try (nmc);
+ if (nmc->complete)
+ return nmc->return_value;
if (argc == 0) {
- if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
- g_string_printf (nmc->return_text, _("Error: %s."), error->message);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
- show_nm_status (nmc, NULL, NULL);
- }
+ /* no arguments -> get hostname */
+ char *hostname = NULL;
+
+ nmc->get_client (nmc); /* create NMClient */
+ g_object_get (nmc->client, NM_CLIENT_HOSTNAME, &hostname, NULL);
+ if (hostname)
+ g_print ("%s\n", hostname);
+ g_free (hostname);
+ } else {
+ /* hostname provided -> set it */
+ const char *hostname = *argv;
- if (argc > 0) {
- if (nmc_arg_is_help (*argv)) {
- usage_general ();
- }
- else if (matches (*argv, "status") == 0) {
- if (nmc_arg_is_help (*(argv+1))) {
- usage_general_status ();
- goto finish;
- }
- if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
- g_string_printf (nmc->return_text, _("Error: %s."), error->message);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
- show_nm_status (nmc, NULL, NULL);
- }
- else if (matches (*argv, "hostname") == 0) {
- if (nmc_arg_is_help (*(argv+1))) {
- usage_general_hostname ();
- goto finish;
- }
+ if (next_arg (&argc, &argv) == 0)
+ g_print ("Warning: ignoring extra garbage after '%s' hostname\n", hostname);
- if (next_arg (&argc, &argv) != 0) {
- /* no arguments -> get hostname */
- char *hostname = NULL;
+ nmc->should_wait++;
+ nmc->get_client (nmc); /* create NMClient */
+ nm_client_save_hostname_async (nmc->client, hostname, NULL, save_hostname_cb, nmc);
+ }
- nmc->get_client (nmc); /* create NMClient */
- g_object_get (nmc->client, NM_CLIENT_HOSTNAME, &hostname, NULL);
- if (hostname)
- g_print ("%s\n", hostname);
- g_free (hostname);
- } else {
- /* hostname provided -> set it */
- const char *hostname = *argv;
+ return nmc->return_value;
- if (next_arg (&argc, &argv) == 0)
- g_print ("Warning: ignoring extra garbage after '%s' hostname\n", hostname);
+}
- nmc->should_wait++;
- nmc->get_client (nmc); /* create NMClient */
- nm_client_save_hostname_async (nmc->client, hostname, NULL, save_hostname_cb, nmc);
- }
- }
- else if (matches (*argv, "permissions") == 0) {
- if (nmc_arg_is_help (*(argv+1))) {
- usage_general_permissions ();
- goto finish;
- }
- if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
- g_string_printf (nmc->return_text, _("Error: %s."), error->message);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
- show_nm_permissions (nmc);
- }
- else if (matches (*argv, "logging") == 0) {
- if (nmc_arg_is_help (*(argv+1))) {
- usage_general_logging ();
- goto finish;
- }
- if (next_arg (&argc, &argv) != 0) {
- /* no arguments -> get logging level and domains */
- if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
- g_string_printf (nmc->return_text, _("Error: %s."), error->message);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
- }
- show_general_logging (nmc);
- } else {
- /* arguments provided -> set logging level and domains */
- const char *level = NULL;
- const char *domains = NULL;
- nmc_arg_t exp_args[] = { {"level", TRUE, &level, TRUE},
- {"domains", TRUE, &domains, TRUE},
- {NULL} };
-
- if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, &error)) {
- g_string_assign (nmc->return_text, error->message);
- nmc->return_value = error->code;
- goto finish;
- }
+static const NMCCommand general_cmds[] = {
+ {"status", do_general_status, usage_general_status },
+ {"hostname", do_general_hostname, usage_general_hostname },
+ {"permissions", do_general_permissions, usage_general_permissions },
+ {"logging", do_general_logging, usage_general_logging },
+ {NULL, do_general_status, usage_general }
+};
- nmc->get_client (nmc); /* create NMClient */
- nm_client_set_logging (nmc->client, level, domains, &error);
- if (error) {
- g_string_printf (nmc->return_text, _("Error: failed to set logging: %s"),
- error->message);
- nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
- goto finish;
- }
- }
- }
- else {
- usage_general ();
- g_string_printf (nmc->return_text, _("Error: 'general' command '%s' is not valid."), *argv);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- }
- }
+/*
+ * Entry point function for general operations 'nmcli general'
+ */
+NMCResultCode
+do_general (NmCli *nmc, int argc, char **argv)
+{
+ /* Register polkit agent */
+ nmc_start_polkit_agent_start_try (nmc);
-finish:
- if (error)
- g_error_free (error);
- return nmc->return_value;
+ return nmc_do_cmd (nmc, general_cmds, *argv, argc, argv);
}
static gboolean
@@ -744,12 +750,28 @@ do_networking (NmCli *nmc, int argc, char **argv)
/* Register polkit agent */
nmc_start_polkit_agent_start_try (nmc);
- if (argc == 0)
+ if (argc == 0) {
+ if (nmc->complete)
+ return nmc->return_value;
nmc_switch_show (nmc, NMC_FIELDS_NM_NETWORKING, _("Networking"));
- else if (argc > 0) {
+ } else if (argc > 0) {
+
+ if (argc == 1 && nmc->complete) {
+ nmc_complete_strings (*argv, "connectivity", NULL);
+ nmc_complete_bool (*argv);
+ return nmc->return_value;
+ }
+
if (nmc_arg_is_help (*argv)) {
+ if (nmc->complete)
+ return nmc->return_value;
usage_networking ();
} else if (matches (*argv, "connectivity") == 0) {
+ if (nmc->complete) {
+ if (argc == 2)
+ nmc_complete_strings (*(argv+1), "check", NULL);
+ return nmc->return_value;
+ }
if (nmc_arg_is_help (*(argv+1))) {
usage_networking_connectivity ();
goto finish;
@@ -774,6 +796,8 @@ do_networking (NmCli *nmc, int argc, char **argv)
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
}
} else if (nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag)) {
+ if (nmc->complete)
+ return nmc->return_value;
if (nmc_arg_is_help (*(argv+1))) {
if (enable_flag)
usage_networking_on ();
@@ -785,6 +809,8 @@ do_networking (NmCli *nmc, int argc, char **argv)
nmc->get_client (nmc); /* create NMClient */
nm_client_networking_set_enabled (nmc->client, enable_flag, NULL);
} else {
+ if (nmc->complete)
+ return nmc->return_value;
usage_networking ();
g_string_printf (nmc->return_text, _("Error: 'networking' command '%s' is not valid."), *argv);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
@@ -796,100 +822,114 @@ finish:
return nmc->return_value;
}
-/*
- * Entry point function for radio switch commands 'nmcli radio'
- */
-NMCResultCode
-do_radio (NmCli *nmc, int argc, char **argv)
+static NMCResultCode
+do_radio_all (NmCli *nmc, int argc, char **argv)
{
- GError *error = NULL;
gboolean enable_flag;
-
- /* Register polkit agent */
- nmc_start_polkit_agent_start_try (nmc);
+ gs_free_error GError *error = NULL;
if (argc == 0) {
+ if (nmc->complete)
+ return nmc->return_value;
+
+ /* no argument, show all radio switches */
if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
g_string_printf (nmc->return_text, _("Error: %s."), error->message);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- g_error_free (error);
- goto finish;
+ return NMC_RESULT_ERROR_USER_INPUT;
}
show_nm_status (nmc, _("Radio switches"), NMC_FIELDS_NM_STATUS_RADIO);
+ } else {
+ if (nmc->complete) {
+ if (argc == 1)
+ nmc_complete_bool (*argv);
+ return nmc->return_value;
+ }
+
+ if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
+ return nmc->return_value;
+
+ nmc->get_client (nmc); /* create NMClient */
+ nm_client_wireless_set_enabled (nmc->client, enable_flag);
+ nm_client_wimax_set_enabled (nmc->client, enable_flag);
+ nm_client_wwan_set_enabled (nmc->client, enable_flag);
}
- if (argc > 0) {
- if (nmc_arg_is_help (*argv)) {
- usage_radio ();
- }
- else if (matches (*argv, "all") == 0) {
- if (nmc_arg_is_help (*(argv+1))) {
- usage_radio_all ();
- goto finish;
- }
- if (next_arg (&argc, &argv) != 0) {
- /* no argument, show all radio switches */
- if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
- g_string_printf (nmc->return_text, _("Error: %s."), error->message);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- g_error_free (error);
- goto finish;
- }
- show_nm_status (nmc, _("Radio switches"), NMC_FIELDS_NM_STATUS_RADIO);
- } else {
- if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
- goto finish;
+ return nmc->return_value;
+}
- nmc->get_client (nmc); /* create NMClient */
- nm_client_wireless_set_enabled (nmc->client, enable_flag);
- nm_client_wimax_set_enabled (nmc->client, enable_flag);
- nm_client_wwan_set_enabled (nmc->client, enable_flag);
- }
- }
- else if (matches (*argv, "wifi") == 0) {
- if (nmc_arg_is_help (*(argv+1))) {
- usage_radio_wifi ();
- goto finish;
- }
- if (next_arg (&argc, &argv) != 0) {
- /* no argument, show current WiFi state */
- nmc_switch_show (nmc, NMC_FIELDS_NM_WIFI, _("Wi-Fi radio switch"));
- } else {
- if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
- goto finish;
-
- nmc->get_client (nmc); /* create NMClient */
- nm_client_wireless_set_enabled (nmc->client, enable_flag);
- }
- }
- else if (matches (*argv, "wwan") == 0) {
- if (nmc_arg_is_help (*(argv+1))) {
- usage_radio_wwan ();
- goto finish;
- }
- if (next_arg (&argc, &argv) != 0) {
- /* no argument, show current WWAN (mobile broadband) state */
- nmc_switch_show (nmc, NMC_FIELDS_NM_WWAN, _("WWAN radio switch"));
- } else {
- if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
- goto finish;
+static NMCResultCode
+do_radio_wifi (NmCli *nmc, int argc, char **argv)
+{
+ gboolean enable_flag;
- nmc->get_client (nmc); /* create NMClient */
- nm_client_wwan_set_enabled (nmc->client, enable_flag);
- }
+ if (argc == 0) {
+ if (nmc->complete)
+ return nmc->return_value;
+
+ /* no argument, show current WiFi state */
+ nmc_switch_show (nmc, NMC_FIELDS_NM_WIFI, _("Wi-Fi radio switch"));
+ } else {
+ if (nmc->complete) {
+ if (argc == 1)
+ nmc_complete_bool (*argv);
+ return nmc->return_value;
}
- else {
- usage_radio ();
- g_string_printf (nmc->return_text, _("Error: 'radio' command '%s' is not valid."), *argv);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
+ return nmc->return_value;
+
+ nmc->get_client (nmc); /* create NMClient */
+ nm_client_wireless_set_enabled (nmc->client, enable_flag);
+ }
+
+ return nmc->return_value;
+}
+
+static NMCResultCode
+do_radio_wwan (NmCli *nmc, int argc, char **argv)
+{
+ gboolean enable_flag;
+
+ if (argc == 0) {
+ if (nmc->complete)
+ return nmc->return_value;
+
+ /* no argument, show current WWAN (mobile broadband) state */
+ nmc_switch_show (nmc, NMC_FIELDS_NM_WWAN, _("WWAN radio switch"));
+ } else {
+ if (nmc->complete) {
+ if (argc == 1)
+ nmc_complete_bool (*argv);
+ return nmc->return_value;
}
+ if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
+ return nmc->return_value;
+
+ nmc->get_client (nmc); /* create NMClient */
+ nm_client_wwan_set_enabled (nmc->client, enable_flag);
}
-finish:
- quit ();
return nmc->return_value;
}
+static const NMCCommand radio_cmds[] = {
+ {"all", do_radio_all, usage_radio_all },
+ {"wifi", do_radio_wifi, usage_radio_wifi },
+ {"wwan", do_radio_wwan, usage_radio_wwan },
+ {NULL, do_radio_all, usage_radio }
+};
+
+/*
+ * Entry point function for radio switch commands 'nmcli radio'
+ */
+NMCResultCode
+do_radio (NmCli *nmc, int argc, char **argv)
+{
+ /* Register polkit agent */
+ nmc_start_polkit_agent_start_try (nmc);
+
+ return nmc_do_cmd (nmc, radio_cmds, *argv, argc, argv);
+}
+
static void
networkmanager_running (NMClient *client, GParamSpec *param, NmCli *nmc)
{
@@ -1181,6 +1221,9 @@ do_overview (NmCli *nmc, int argc, char **argv)
NMCResultCode
do_monitor (NmCli *nmc, int argc, char **argv)
{
+ if (nmc->complete)
+ return nmc->return_value;
+
if (argc > 0) {
if (!nmc_arg_is_help (*argv)) {
g_string_printf (nmc->return_text, _("Error: 'monitor' command '%s' is not valid."), *argv);
diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c
index 0a8dcb5b74..9bfa05fade 100644
--- a/clients/cli/nmcli.c
+++ b/clients/cli/nmcli.c
@@ -41,6 +41,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 +65,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 +178,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,15 +203,7 @@ 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 NMCCommand nmcli_cmds[] = {
@@ -122,8 +214,7 @@ static const NMCCommand nmcli_cmds[] = {
{ "connection", do_connections, NULL },
{ "device", do_devices, NULL },
{ "agent", do_agent, NULL },
- { "help", do_help, NULL },
- { NULL, do_overview, NULL },
+ { NULL, do_overview, usage }
};
static NMCResultCode
@@ -137,29 +228,33 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
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") || nm_streq0 (argv[2], "device")))
- return nmc->return_value;
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."));
@@ -188,63 +283,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) {
@@ -253,24 +352,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);
@@ -282,7 +382,7 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
}
/* Now run the requested command */
- return nmc_do_cmd (nmc, nmcli_cmds, argv[1], argc-1, argv+1);
+ return nmc_do_cmd (nmc, nmcli_cmds, *argv, argc, argv);
}
static gboolean nmcli_sigint = FALSE;
@@ -617,11 +717,12 @@ main (int argc, char *argv[])
loop = g_main_loop_new (NULL, FALSE); /* create main loop */
g_main_loop_run (loop); /* run main loop */
- if (nm_cli.complete)
- nm_cli.return_value = NMC_RESULT_SUCCESS;
-
- /* 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);
}
diff --git a/clients/cli/nmcli.h b/clients/cli/nmcli.h
index c867ad5f9f..a8908685bd 100644
--- a/clients/cli/nmcli.h
+++ b/clients/cli/nmcli.h
@@ -63,7 +63,10 @@ typedef enum {
NMC_RESULT_ERROR_VERSIONS_MISMATCH = 9,
/* Connection/Device/AP not found */
- NMC_RESULT_ERROR_NOT_FOUND = 10
+ NMC_RESULT_ERROR_NOT_FOUND = 10,
+
+ /* --complete-args signals a file name may follow */
+ NMC_RESULT_COMPLETE_FILE = 65,
} NMCResultCode;
typedef enum {
diff --git a/clients/cli/settings.c b/clients/cli/settings.c
index 98d0c8b19d..feed51ce7e 100644
--- a/clients/cli/settings.c
+++ b/clients/cli/settings.c
@@ -3247,8 +3247,7 @@ nmc_property_connection_set_secondaries (NMSetting *setting, const char *prop, c
continue;
if (nm_utils_is_uuid (*iter)) {
- con = nmc_find_connection (nm_cli.connections,
- "uuid", *iter, NULL);
+ con = nmc_find_connection (nm_cli.connections, "uuid", *iter, NULL, FALSE);
if (!con)
g_print (_("Warning: %s is not an UUID of any existing connection profile\n"), *iter);
else {
@@ -3260,8 +3259,7 @@ nmc_property_connection_set_secondaries (NMSetting *setting, const char *prop, c
}
}
} else {
- con = nmc_find_connection (nm_cli.connections,
- "id", *iter, NULL);
+ con = nmc_find_connection (nm_cli.connections, "id", *iter, NULL, FALSE);
if (!con) {
g_set_error (error, 1, 0, _("'%s' is not a name of any exiting profile"), *iter);
g_strfreev (strv);
diff --git a/clients/cli/settings.h b/clients/cli/settings.h
index bab00ee908..33900510fd 100644
--- a/clients/cli/settings.h
+++ b/clients/cli/settings.h
@@ -63,4 +63,34 @@ gboolean nmc_property_set_gvalue (NMSetting *setting, const char *prop, GValue *
gboolean setting_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gboolean secrets);
+extern NmcOutputField nmc_fields_setting_connection[];
+extern NmcOutputField nmc_fields_setting_wired[];
+extern NmcOutputField nmc_fields_setting_8021X[];
+extern NmcOutputField nmc_fields_setting_wireless[];
+extern NmcOutputField nmc_fields_setting_wireless_security[];
+extern NmcOutputField nmc_fields_setting_ip4_config[];
+extern NmcOutputField nmc_fields_setting_ip6_config[];
+extern NmcOutputField nmc_fields_setting_serial[];
+extern NmcOutputField nmc_fields_setting_ppp[];
+extern NmcOutputField nmc_fields_setting_pppoe[];
+extern NmcOutputField nmc_fields_setting_adsl[];
+extern NmcOutputField nmc_fields_setting_gsm[];
+extern NmcOutputField nmc_fields_setting_cdma[];
+extern NmcOutputField nmc_fields_setting_bluetooth[];
+extern NmcOutputField nmc_fields_setting_olpc_mesh[];
+extern NmcOutputField nmc_fields_setting_vpn[];
+extern NmcOutputField nmc_fields_setting_wimax[];
+extern NmcOutputField nmc_fields_setting_infiniband[];
+extern NmcOutputField nmc_fields_setting_bond[];
+extern NmcOutputField nmc_fields_setting_vlan[];
+extern NmcOutputField nmc_fields_setting_bridge[];
+extern NmcOutputField nmc_fields_setting_bridge_port[];
+extern NmcOutputField nmc_fields_setting_team[];
+extern NmcOutputField nmc_fields_setting_team_port[];
+extern NmcOutputField nmc_fields_setting_dcb[];
+extern NmcOutputField nmc_fields_setting_tun[];
+extern NmcOutputField nmc_fields_setting_ip_tunnel[];
+extern NmcOutputField nmc_fields_setting_macvlan[];
+extern NmcOutputField nmc_fields_setting_vxlan[];
+
#endif /* NMC_SETTINGS_H */
diff --git a/man/nmcli.xml b/man/nmcli.xml
index 0d403202f4..5a936335c0 100644
--- a/man/nmcli.xml
+++ b/man/nmcli.xml
@@ -278,6 +278,23 @@
<varlistentry>
<term><group choice='plain'>
+ <arg choice='plain'><option>--complete-args</option></arg>
+ </group></term>
+
+ <listitem>
+ <para>Instead of conducting the desired action, <command>nmcli</command>
+ will list possible completions for the last argument. This is useful to implement
+ argument completion in shell.</para>
+
+ <para>The <link linkend='exit_status'>exit status</link> will indicate success
+ or return a code 65 to indicate the last argument is a file name.</para>
+
+ <para>NetworkManager ships with command completion support for GNU Bash.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><group choice='plain'>
<arg choice='plain'><option>-v</option></arg>
<arg choice='plain'><option>--version</option></arg>
</group></term>
@@ -2089,6 +2106,13 @@ It's equivalent of using <literal>+ipv6.addresses</literal> syntax.</entry>
<para>Connection, device, or access point does not exist.</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><errorcode>65</errorcode></term>
+ <listitem>
+ <para>When used with <option>--complete-args</option> option, a file name is expected to follow.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>