summary refs log tree commit diff
path: root/clients/cli
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2018-04-23 18:00:21 +0200
committerMichael Biebl <biebl@debian.org>2018-04-23 18:00:21 +0200
commitf60117b41d5433be1b4a96d82cd11d0c3dce9b63 (patch)
tree2dd55c4ab0fdcbe9cddb26adb4a554b1a45c73c8 /clients/cli
parent7e9ff09fcb2366b383b7ebbec80d2f6fff117290 (diff)
New upstream version 1.11.3 upstream/1.11.3
Diffstat (limited to 'clients/cli')
-rw-r--r--clients/cli/agent.c2
-rw-r--r--clients/cli/common.c129
-rw-r--r--clients/cli/connections.c238
-rw-r--r--clients/cli/devices.c7
-rw-r--r--clients/cli/general.c3
-rw-r--r--clients/cli/meson.build48
-rw-r--r--clients/cli/nmcli.c20
-rw-r--r--clients/cli/nmcli.h12
-rw-r--r--clients/cli/polkit-agent.c73
-rw-r--r--clients/cli/settings.c9
-rw-r--r--clients/cli/utils.c27
-rw-r--r--clients/cli/utils.h2
12 files changed, 337 insertions, 233 deletions
diff --git a/clients/cli/agent.c b/clients/cli/agent.c
index 488b16f4..46725c94 100644
--- a/clients/cli/agent.c
+++ b/clients/cli/agent.c
@@ -104,7 +104,7 @@ get_secrets_from_user (const char *request_id,
 			rl_startup_hook = set_deftext;
 			pre_input_deftext = g_strdup (secret->value);
 		}
-		pwd = nmc_readline ("%s (%s): ", secret->name, secret->prop_name);
+		pwd = nmc_readline ("%s (%s): ", secret->pretty_name, secret->entry_id);
 
 		/* No password provided, cancel the secrets. */
 		if (!pwd)
diff --git a/clients/cli/common.c b/clients/cli/common.c
index 0f5aea57..81a3183d 100644
--- a/clients/cli/common.c
+++ b/clients/cli/common.c
@@ -16,7 +16,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright 2012 - 2014 Red Hat, Inc.
+ * Copyright 2012 - 2017 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -26,12 +26,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
-#include <termios.h>
 #include <sys/ioctl.h>
 #include <readline/readline.h>
 #include <readline/history.h>
 
-#include "nm-utils/nm-hash-utils.h"
 #include "nm-vpn-helpers.h"
 #include "nm-client-utils.h"
 
@@ -109,6 +107,7 @@ _metagen_ip4_config_get_fcn (const NMMetaEnvironment *environment,
                              NMMetaAccessorGetType get_type,
                              NMMetaAccessorGetFlags get_flags,
                              NMMetaAccessorGetOutFlags *out_flags,
+                             gboolean *out_is_default,
                              gpointer *out_to_free)
 {
 	NMIPConfig *cfg4 = target;
@@ -116,10 +115,12 @@ _metagen_ip4_config_get_fcn (const NMMetaEnvironment *environment,
 	char **arr;
 	const char *const*arrc;
 	guint i = 0;
+	const char *str;
 
 	nm_assert (info->info_type < _NMC_GENERIC_INFO_TYPE_IP4_CONFIG_NUM);
 
 	NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL);
+	NM_SET_OUT (out_is_default, TRUE);
 
 	switch (info->info_type) {
 	case NMC_GENERIC_INFO_TYPE_IP4_CONFIG_ADDRESS:
@@ -140,7 +141,9 @@ _metagen_ip4_config_get_fcn (const NMMetaEnvironment *environment,
 			arr = NULL;
 		goto arr_out;
 	case NMC_GENERIC_INFO_TYPE_IP4_CONFIG_GATEWAY:
-		return nm_ip_config_get_gateway (cfg4);
+		str = nm_ip_config_get_gateway (cfg4);
+		NM_SET_OUT (out_is_default, !str);
+		return str;
 	case NMC_GENERIC_INFO_TYPE_IP4_CONFIG_ROUTE:
 		if (!NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_ACCEPT_STRV))
 			return NULL;
@@ -168,10 +171,12 @@ _metagen_ip4_config_get_fcn (const NMMetaEnvironment *environment,
 	g_return_val_if_reached (NULL);
 
 arrc_out:
+	NM_SET_OUT (out_is_default, !arrc || !arrc[0]);
 	*out_flags |= NM_META_ACCESSOR_GET_OUT_FLAGS_STRV;
 	return arrc;
 
 arr_out:
+	NM_SET_OUT (out_is_default, !arr || !arr[0]);
 	*out_flags |= NM_META_ACCESSOR_GET_OUT_FLAGS_STRV;
 	*out_to_free = arr;
 	return arr;
@@ -185,6 +190,7 @@ _metagen_ip6_config_get_fcn (const NMMetaEnvironment *environment,
                              NMMetaAccessorGetType get_type,
                              NMMetaAccessorGetFlags get_flags,
                              NMMetaAccessorGetOutFlags *out_flags,
+                             gboolean *out_is_default,
                              gpointer *out_to_free)
 {
 	NMIPConfig *cfg6 = target;
@@ -192,10 +198,12 @@ _metagen_ip6_config_get_fcn (const NMMetaEnvironment *environment,
 	char **arr;
 	const char *const*arrc;
 	guint i = 0;
+	const char *str;
 
 	nm_assert (info->info_type < _NMC_GENERIC_INFO_TYPE_IP6_CONFIG_NUM);
 
 	NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL);
+	NM_SET_OUT (out_is_default, TRUE);
 
 	switch (info->info_type) {
 	case NMC_GENERIC_INFO_TYPE_IP6_CONFIG_ADDRESS:
@@ -216,7 +224,9 @@ _metagen_ip6_config_get_fcn (const NMMetaEnvironment *environment,
 			arr = NULL;
 		goto arr_out;
 	case NMC_GENERIC_INFO_TYPE_IP6_CONFIG_GATEWAY:
-		return nm_ip_config_get_gateway (cfg6);
+		str = nm_ip_config_get_gateway (cfg6);
+		NM_SET_OUT (out_is_default, !str);
+		return str;
 	case NMC_GENERIC_INFO_TYPE_IP6_CONFIG_ROUTE:
 		if (!NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_ACCEPT_STRV))
 			return NULL;
@@ -239,10 +249,12 @@ _metagen_ip6_config_get_fcn (const NMMetaEnvironment *environment,
 	g_return_val_if_reached (NULL);
 
 arrc_out:
+	NM_SET_OUT (out_is_default, !arrc || !arrc[0]);
 	*out_flags |= NM_META_ACCESSOR_GET_OUT_FLAGS_STRV;
 	return arrc;
 
 arr_out:
+	NM_SET_OUT (out_is_default, !arr || !arr[0]);
 	*out_flags |= NM_META_ACCESSOR_GET_OUT_FLAGS_STRV;
 	*out_to_free = arr;
 	return arr;
@@ -532,10 +544,10 @@ vpn_openconnect_get_secrets (NMConnection *connection, GPtrArray *secrets)
 {
 	GError *error = NULL;
 	NMSettingVpn *s_vpn;
-	const char *vpn_type, *gw, *port;
-	char *cookie = NULL;
-	char *gateway = NULL;
-	char *gwcert = NULL;
+	const char *gw, *port;
+	gs_free char *cookie = NULL;
+	gs_free char *gateway = NULL;
+	gs_free char *gwcert = NULL;
 	int status = 0;
 	int i;
 	gboolean ret;
@@ -547,8 +559,7 @@ vpn_openconnect_get_secrets (NMConnection *connection, GPtrArray *secrets)
 		return FALSE;
 
 	s_vpn = nm_connection_get_setting_vpn (connection);
-	vpn_type = nm_setting_vpn_get_service_type (s_vpn);
-	if (g_strcmp0 (vpn_type, NM_DBUS_INTERFACE ".openconnect"))
+	if (!nm_streq0 (nm_setting_vpn_get_service_type (s_vpn), NM_SECRET_AGENT_VPN_TYPE_OPENCONNECT))
 		return FALSE;
 
 	/* Get gateway and port */
@@ -571,34 +582,31 @@ vpn_openconnect_get_secrets (NMConnection *connection, GPtrArray *secrets)
 
 	/* Append port to the host value */
 	if (gateway && port) {
-		char *tmp = gateway;
-		gateway = g_strdup_printf ("%s%s", gateway, port);
-		g_free (tmp);
+		gs_free char *tmp = gateway;
+
+		gateway = g_strdup_printf ("%s%s", tmp, port);
 	}
 
 	/* Fill secrets to the array */
 	for (i = 0; i < secrets->len; i++) {
 		NMSecretAgentSimpleSecret *secret = secrets->pdata[i];
 
-		if (!g_strcmp0 (secret->vpn_type, vpn_type)) {
-			if (!g_strcmp0 (secret->vpn_property, "cookie")) {
-				g_free (secret->value);
-				secret->value = cookie;
-				cookie = NULL;
-			} else if (!g_strcmp0 (secret->vpn_property, "gateway")) {
-				g_free (secret->value);
-				secret->value = gateway;
-				gateway = NULL;
-			} else if (!g_strcmp0 (secret->vpn_property, "gwcert")) {
-				g_free (secret->value);
-				secret->value = gwcert;
-				gwcert = NULL;
-			}
+		if (secret->secret_type != NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET)
+			continue;
+		if (!nm_streq0 (secret->vpn_type, NM_SECRET_AGENT_VPN_TYPE_OPENCONNECT))
+			continue;
+
+		if (nm_streq0 (secret->entry_id, NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET "cookie")) {
+			g_free (secret->value);
+			secret->value = g_steal_pointer (&cookie);
+		} else if (nm_streq0 (secret->entry_id, NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET "gateway")) {
+			g_free (secret->value);
+			secret->value = g_steal_pointer (&gateway);
+		} else if (nm_streq0 (secret->entry_id, NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRET "gwcert")) {
+			g_free (secret->value);
+			secret->value = g_steal_pointer (&gwcert);
 		}
 	}
-	g_free (cookie);
-	g_free (gateway);
-	g_free (gwcert);
 
 	return TRUE;
 }
@@ -625,7 +633,7 @@ get_secrets_from_user (const char *request_id,
 
 		/* First try to find the password in provided passwords file,
 		 * then ask user. */
-		if (pwds_hash && (pwd = g_hash_table_lookup (pwds_hash, secret->prop_name))) {
+		if (pwds_hash && (pwd = g_hash_table_lookup (pwds_hash, secret->entry_id))) {
 			pwd = g_strdup (pwd);
 		} else {
 			if (ask) {
@@ -641,8 +649,10 @@ get_secrets_from_user (const char *request_id,
 				}
 				if (msg)
 					g_print ("%s\n", msg);
-				pwd = nmc_readline_echo (secret->password ? echo_on : TRUE,
-				                         "%s (%s): ", secret->name, secret->prop_name);
+				pwd = nmc_readline_echo (secret->is_secret
+				                         ? echo_on
+				                         : TRUE,
+				                         "%s (%s): ", secret->pretty_name, secret->entry_id);
 				if (!pwd)
 					pwd = g_strdup ("");
 			} else {
@@ -650,7 +660,7 @@ get_secrets_from_user (const char *request_id,
 					g_print ("%s\n", msg);
 				g_printerr (_("Warning: password for '%s' not given in 'passwd-file' "
 				              "and nmcli cannot ask without '--ask' option.\n"),
-				            secret->prop_name);
+				            secret->entry_id);
 			}
 		}
 		/* No password provided, cancel the secrets. */
@@ -883,6 +893,31 @@ nmc_readline (const char *prompt_fmt, ...)
 	return str;
 }
 
+static void
+nmc_secret_redisplay (void)
+{
+	int save_point = rl_point;
+	int save_end = rl_end;
+	char *save_line_buffer = rl_line_buffer;
+	const char *subst = nmc_password_subst_char ();
+	int subst_len = strlen (subst);
+	int i;
+
+	rl_point = g_utf8_strlen (save_line_buffer, save_point) * subst_len;
+	rl_end = g_utf8_strlen (rl_line_buffer, -1) * subst_len;
+	rl_line_buffer = g_slice_alloc (rl_end + 1);
+
+	for (i = 0; i + subst_len <= rl_end; i += subst_len)
+		memcpy (&rl_line_buffer[i], subst, subst_len);
+	rl_line_buffer[i] = '\0';
+
+	rl_redisplay ();
+	g_slice_free1 (rl_end + 1, rl_line_buffer);
+	rl_line_buffer = save_line_buffer;
+	rl_end = save_end;
+	rl_point = save_point;
+}
+
 /**
  * nmc_readline_echo:
  *
@@ -894,29 +929,28 @@ nmc_readline_echo (gboolean echo_on, const char *prompt_fmt, ...)
 {
 	va_list args;
 	char *prompt, *str;
-	struct termios termios_orig, termios_new;
+	HISTORY_STATE *saved_history;
+	HISTORY_STATE passwd_history = { 0, };
 
 	va_start (args, prompt_fmt);
 	prompt = g_strdup_vprintf (prompt_fmt, args);
 	va_end (args);
 
-	/* Disable echoing characters */
+	/* Hide the actual password */
 	if (!echo_on) {
-		tcgetattr (STDIN_FILENO, &termios_orig);
-		termios_new = termios_orig;
-		termios_new.c_lflag &= ~(ECHO);
-		tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_new);
+		saved_history = history_get_history_state ();
+		history_set_history_state (&passwd_history);
+		rl_redisplay_function = nmc_secret_redisplay;
 	}
 
 	str = nmc_readline_helper (prompt);
 
 	g_free (prompt);
 
-	/* Restore original terminal settings */
+	/* Restore the non-hiding behavior */
 	if (!echo_on) {
-		tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_orig);
-		/* New line - setting ECHONL | ICANON did not help */
-		fprintf (stdout, "\n");
+		rl_redisplay_function = rl_redisplay;
+		history_set_history_state (saved_history);
 	}
 
 	return str;
@@ -1215,9 +1249,8 @@ nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char
 		/* A valid command was specified. */
 		if (c->usage && argc == 2 && nmc->complete)
 			nmc_complete_help (*(argv+1));
-		if (c->usage && nmc_arg_is_help (*(argv+1))) {
-			if (!nmc->complete)
-				c->usage ();
+		if (!nmc->complete && c->usage && nmc_arg_is_help (*(argv+1))) {
+			c->usage ();
 			g_simple_async_result_complete_in_idle (simple);
 			g_object_unref (simple);
 		} else {
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index e0f55c53..705d3c25 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -31,8 +31,6 @@
 #include <readline/readline.h>
 #include <readline/history.h>
 
-#include "nm-utils/nm-hash-utils.h"
-
 #include "nm-client-utils.h"
 #include "nm-vpn-helpers.h"
 #include "nm-meta-setting-access.h"
@@ -505,12 +503,8 @@ usage_connection_export (void)
 static void
 quit (void)
 {
-	if (progress_id) {
-		g_source_remove (progress_id);
-		progress_id = 0;
+	if (nm_clear_g_source (&progress_id))
 		nmc_terminal_erase_line ();
-	}
-
 	g_main_loop_quit (loop);
 }
 
@@ -1128,7 +1122,6 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
 	const char *fields_str = NULL;
 	const NMMetaAbstractInfo *const*tmpl;
 	NmcOutputField *arr;
-	size_t tmpl_len;
 	const char *base_hdr = _("Activate connection details");
 	gboolean was_output = FALSE;
 
@@ -1182,7 +1175,6 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
 
 			/* Add field names */
 			tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_general;
-			tmpl_len = sizeof (nmc_fields_con_active_details_general);
 			out_indices = parse_output_fields (group_fld,
 			                                   tmpl, FALSE, NULL, NULL);
 			arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_FIELD_NAMES);
@@ -1589,18 +1581,18 @@ get_invisible_active_connections (NmCli *nmc)
 static GArray *
 parse_preferred_connection_order (const char *order, GError **error)
 {
-	char **strv, **iter;
+	gs_free const char **strv = NULL;
+	const char *const*iter;
 	const char *str;
 	GArray *order_arr;
 	NmcSortOrder val;
 	gboolean inverse, unique;
 	int i;
 
-	strv = nmc_strsplit_set (order, ":", -1);
-	if (!strv || !*strv) {
+	strv = nm_utils_strsplit_set (order, ":");
+	if (!strv) {
 		g_set_error (error, NMCLI_ERROR, 0,
 		             _("incorrect string '%s' of '--order' option"), order);
-		g_strfreev (strv);
 		return NULL;
 	}
 
@@ -1642,7 +1634,6 @@ parse_preferred_connection_order (const char *order, GError **error)
 			g_array_append_val (order_arr, val);
 	}
 
-	g_strfreev (strv);
 	return order_arr;
 }
 
@@ -1662,16 +1653,17 @@ get_connection (NmCli *nmc, int *argc, char ***argv, int *pos, GError **error)
 	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;
-		(*argc)--;
-		(*argv)++;
-		if (!*argc) {
-			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
-			             _("%s argument is missing"), selector);
-			return NULL;
+	if (NM_IN_STRSET (**argv, "id", "uuid", "path")) {
+		if (*argc == 1) {
+			if (!nmc->complete) {
+				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+				             _("%s argument is missing"), selector);
+				return NULL;
+			}
+		} else {
+			selector = **argv;
+			(*argv)++;
+			(*argc)--;
 		}
 	}
 
@@ -2295,48 +2287,50 @@ activate_connection_cb (GObject *client, GAsyncResult *result, gpointer user_dat
 static GHashTable *
 parse_passwords (const char *passwd_file, GError **error)
 {
-	GHashTable *pwds_hash;
-	char *contents = NULL;
+	gs_unref_hashtable GHashTable *pwds_hash = NULL;
+	gs_free char *contents = NULL;
 	gsize len = 0;
 	GError *local_err = NULL;
-	char **lines, **iter;
+	gs_free const char **strv = NULL;
+	const char *const*iter;
 	char *pwd_spec, *pwd, *prop;
 	const char *setting;
 
 	pwds_hash = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free);
 
 	if (!passwd_file)
-		return pwds_hash;
+		return g_steal_pointer (&pwds_hash);
 
-        /* Read the passwords file */
+	/* Read the passwords file */
 	if (!g_file_get_contents (passwd_file, &contents, &len, &local_err)) {
 		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
 		             _("failed to read passwd-file '%s': %s"),
 		             passwd_file, local_err->message);
 		g_error_free (local_err);
-		g_hash_table_destroy (pwds_hash);
 		return NULL;
 	}
 
-	lines = nmc_strsplit_set (contents, "\r\n", -1);
-	for (iter = lines; *iter; iter++) {
-		pwd = strchr (*iter, ':');
+	strv = nm_utils_strsplit_set (contents, "\r\n");
+	for (iter = strv; *iter; iter++) {
+		gs_free char *iter_s = g_strdup (*iter);
+
+		pwd = strchr (iter_s, ':');
 		if (!pwd) {
 			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
 			             _("missing colon in 'password' entry '%s'"), *iter);
-			goto failure;
+			return NULL;
 		}
 		*(pwd++) = '\0';
 
-		prop = strchr (*iter, '.');
+		prop = strchr (iter_s, '.');
 		if (!prop) {
 			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
 			             _("missing dot in 'password' entry '%s'"), *iter);
-			goto failure;
+			return NULL;
 		}
 		*(prop++) = '\0';
 
-		setting = *iter;
+		setting = iter_s;
 		while (g_ascii_isspace (*setting))
 			setting++;
 		/* Accept wifi-sec or wifi instead of cumbersome '802-11-wireless-security' */
@@ -2345,21 +2339,13 @@ parse_passwords (const char *passwd_file, GError **error)
 		if (nm_setting_lookup_type (setting) == G_TYPE_INVALID) {
 			g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
 			             _("invalid setting name in 'password' entry '%s'"), setting);
-			goto failure;
+			return NULL;
 		}
 
 		pwd_spec = g_strdup_printf ("%s.%s", setting, prop);
 		g_hash_table_insert (pwds_hash, pwd_spec, g_strdup (pwd));
 	}
-	g_strfreev (lines);
-	g_free (contents);
-	return pwds_hash;
-
-failure:
-	g_strfreev (lines);
-	g_free (contents);
-	g_hash_table_destroy (pwds_hash);
-	return NULL;
+	return g_steal_pointer (&pwds_hash);
 }
 
 
@@ -3339,7 +3325,7 @@ _dynamic_options_set (const NMMetaAbstractInfo *abstract_info,
 	PropertyInfFlags v, v2;
 
 	if (G_UNLIKELY (!cache))
-		cache = g_hash_table_new (NULL, NULL);
+		cache = g_hash_table_new (nm_direct_hash, NULL);
 
 	if (g_hash_table_lookup_extended (cache, (gpointer) abstract_info, NULL, &p))
 		v = GPOINTER_TO_UINT (p);
@@ -5889,50 +5875,80 @@ typedef enum {
 	NMC_EDITOR_MAIN_CMD_QUIT,
 } NmcEditorMainCmd;
 
+static void
+_split_cmd (const char *cmd, char **out_arg0, const char **out_argr)
+{
+	gs_free char *arg0 = NULL;
+	const char *argr = NULL;
+	gsize l;
+
+	NM_SET_OUT (out_arg0, NULL);
+	NM_SET_OUT (out_argr, NULL);
+
+	if (!cmd)
+		return;
+	while (NM_IN_SET (cmd[0], ' ', '\t'))
+		cmd++;
+	if (!cmd[0])
+		return;
+
+	l = strcspn (cmd, " \t");
+	arg0 = g_strndup (cmd, l);
+	cmd += l;
+	if (cmd[0]) {
+		while (NM_IN_SET (cmd[0], ' ', '\t'))
+			cmd++;
+		if (cmd[0])
+			argr = cmd;
+	}
+
+	NM_SET_OUT (out_arg0, g_steal_pointer (&arg0));
+	NM_SET_OUT (out_argr, argr);
+}
+
 static NmcEditorMainCmd
 parse_editor_main_cmd (const char *cmd, char **cmd_arg)
 {
 	NmcEditorMainCmd editor_cmd = NMC_EDITOR_MAIN_CMD_UNKNOWN;
-	char **vec;
+	gs_free char *cmd_arg0 = NULL;
+	const char *cmd_argr;
 
-	vec = nmc_strsplit_set (cmd, " \t", 2);
-	if (g_strv_length (vec) < 1) {
-		if (cmd_arg)
-			*cmd_arg = NULL;
-		return NMC_EDITOR_MAIN_CMD_UNKNOWN;
-	}
+	_split_cmd (cmd, &cmd_arg0, &cmd_argr);
+	if (!cmd_arg0)
+		goto fail;
 
-	if (matches (vec[0], "goto"))
+	if (matches (cmd_arg0, "goto"))
 		editor_cmd = NMC_EDITOR_MAIN_CMD_GOTO;
-	else if (matches (vec[0], "remove"))
+	else if (matches (cmd_arg0, "remove"))
 		editor_cmd = NMC_EDITOR_MAIN_CMD_REMOVE;
-	else if (matches (vec[0], "set"))
+	else if (matches (cmd_arg0, "set"))
 		editor_cmd = NMC_EDITOR_MAIN_CMD_SET;
-	else if (matches (vec[0], "describe"))
+	else if (matches (cmd_arg0, "describe"))
 		editor_cmd = NMC_EDITOR_MAIN_CMD_DESCRIBE;
-	else if (matches (vec[0], "print"))
+	else if (matches (cmd_arg0, "print"))
 		editor_cmd = NMC_EDITOR_MAIN_CMD_PRINT;
-	else if (matches (vec[0], "verify"))
+	else if (matches (cmd_arg0, "verify"))
 		editor_cmd = NMC_EDITOR_MAIN_CMD_VERIFY;
-	else if (matches (vec[0], "save"))
+	else if (matches (cmd_arg0, "save"))
 		editor_cmd = NMC_EDITOR_MAIN_CMD_SAVE;
-	else if (matches (vec[0], "activate"))
+	else if (matches (cmd_arg0, "activate"))
 		editor_cmd = NMC_EDITOR_MAIN_CMD_ACTIVATE;
-	else if (matches (vec[0], "back"))
+	else if (matches (cmd_arg0, "back"))
 		editor_cmd = NMC_EDITOR_MAIN_CMD_BACK;
-	else if (matches (vec[0], "help") || strcmp (vec[0], "?") == 0)
+	else if (matches (cmd_arg0, "help") || strcmp (cmd_arg0, "?") == 0)
 		editor_cmd = NMC_EDITOR_MAIN_CMD_HELP;
-	else if (matches (vec[0], "quit"))
+	else if (matches (cmd_arg0, "quit"))
 		editor_cmd = NMC_EDITOR_MAIN_CMD_QUIT;
-	else if (matches (vec[0], "nmcli"))
+	else if (matches (cmd_arg0, "nmcli"))
 		editor_cmd = NMC_EDITOR_MAIN_CMD_NMCLI;
+	else
+		goto fail;
 
-	/* set pointer to command argument */
-	if (cmd_arg)
-		*cmd_arg = vec[1] ? g_strstrip (g_strdup (vec[1])) : NULL;
-
-	g_strfreev (vec);
+	NM_SET_OUT (cmd_arg, g_strdup (cmd_argr));
 	return editor_cmd;
+fail:
+	NM_SET_OUT (cmd_arg, NULL);
+	return NMC_EDITOR_MAIN_CMD_UNKNOWN;
 }
 
 static void
@@ -6081,40 +6097,39 @@ static NmcEditorSubCmd
 parse_editor_sub_cmd (const char *cmd, char **cmd_arg)
 {
 	NmcEditorSubCmd editor_cmd = NMC_EDITOR_SUB_CMD_UNKNOWN;
-	char **vec;
+	gs_free char *cmd_arg0 = NULL;
+	const char *cmd_argr;
 
-	vec = nmc_strsplit_set (cmd, " \t", 2);
-	if (g_strv_length (vec) < 1) {
-		if (cmd_arg)
-			*cmd_arg = NULL;
-		return NMC_EDITOR_SUB_CMD_UNKNOWN;
-	}
+	_split_cmd (cmd, &cmd_arg0, &cmd_argr);
+	if (!cmd_arg0)
+		goto fail;
 
-	if (matches (vec[0], "set"))
+	if (matches (cmd_arg0, "set"))
 		editor_cmd = NMC_EDITOR_SUB_CMD_SET;
-	else if (matches (vec[0], "add"))
+	else if (matches (cmd_arg0, "add"))
 		editor_cmd = NMC_EDITOR_SUB_CMD_ADD;
-	else if (matches (vec[0], "change"))
+	else if (matches (cmd_arg0, "change"))
 		editor_cmd = NMC_EDITOR_SUB_CMD_CHANGE;
-	else if (matches (vec[0], "remove"))
+	else if (matches (cmd_arg0, "remove"))
 		editor_cmd = NMC_EDITOR_SUB_CMD_REMOVE;
-	else if (matches (vec[0], "describe"))
+	else if (matches (cmd_arg0, "describe"))
 		editor_cmd = NMC_EDITOR_SUB_CMD_DESCRIBE;
-	else if (matches (vec[0], "print"))
+	else if (matches (cmd_arg0, "print"))
 		editor_cmd = NMC_EDITOR_SUB_CMD_PRINT;
-	else if (matches (vec[0], "back"))
+	else if (matches (cmd_arg0, "back"))
 		editor_cmd = NMC_EDITOR_SUB_CMD_BACK;
-	else if (matches (vec[0], "help") || strcmp (vec[0], "?") == 0)
+	else if (matches (cmd_arg0, "help") || strcmp (cmd_arg0, "?") == 0)
 		editor_cmd = NMC_EDITOR_SUB_CMD_HELP;
-	else if (matches (vec[0], "quit"))
+	else if (matches (cmd_arg0, "quit"))
 		editor_cmd = NMC_EDITOR_SUB_CMD_QUIT;
+	else
+		goto fail;
 
-	/* set pointer to command argument */
-	if (cmd_arg)
-		*cmd_arg = g_strdup (vec[1]);
-
-	g_strfreev (vec);
+	NM_SET_OUT (cmd_arg, g_strdup (cmd_argr));
 	return editor_cmd;
+fail:
+	NM_SET_OUT (cmd_arg, NULL);
+	return NMC_EDITOR_SUB_CMD_UNKNOWN;
 }
 
 static void
@@ -6650,29 +6665,26 @@ property_edit_submenu (NmCli *nmc,
 static void
 split_editor_main_cmd_args (const char *str, char **setting, char **property, char **value)
 {
-	char **args, **items;
+	gs_free char *cmd_arg0 = NULL;
+	const char *cmd_argr;
+	const char *s;
 
-	if (!str)
-		return;
+	NM_SET_OUT (setting, NULL);
+	NM_SET_OUT (property, NULL);
+	NM_SET_OUT (value, NULL);
 
-	args = nmc_strsplit_set (str, " \t", 2);
-	if (args[0]) {
-		items = nmc_strsplit_set (args[0], ".", 2);
-		if (g_strv_length (items) == 2) {
-			if (setting)
-				*setting = g_strdup (items[0]);
-			if (property)
-				*property = g_strdup (items[1]);
-		} else {
-			if (property)
-				*property = g_strdup (items[0]);
-		}
-		g_strfreev (items);
+	_split_cmd (str, &cmd_arg0, &cmd_argr);
+	if (!cmd_arg0)
+		return;
 
-		if (value && args[1])
-			*value = g_strstrip (g_strdup (args[1]));
+	NM_SET_OUT (value, g_strdup (cmd_argr));
+	s = strchr (cmd_arg0, '.');
+	if (s && s > cmd_arg0) {
+		NM_SET_OUT (setting, g_strndup (cmd_arg0, s - cmd_arg0));
+		NM_SET_OUT (property, g_strdup (&s[1]));
+	} else {
+		NM_SET_OUT (property, g_steal_pointer (&cmd_arg0));
 	}
-	g_strfreev (args);
 }
 
 static NMSetting *
@@ -6793,7 +6805,7 @@ confirm_connection_saving (NMConnection *local, NMConnection *remote)
 	return confirmed;
 }
 
-typedef	struct {
+typedef struct {
 	guint level;
 	char *main_prompt;
 	NMSetting *curr_setting;
diff --git a/clients/cli/devices.c b/clients/cli/devices.c
index da969fbe..a43861fa 100644
--- a/clients/cli/devices.c
+++ b/clients/cli/devices.c
@@ -451,11 +451,8 @@ usage_device_lldp (void)
 static void
 quit (void)
 {
-	if (progress_id) {
-		g_source_remove (progress_id);
+	if (nm_clear_g_source (&progress_id))
 		nmc_terminal_erase_line ();
-	}
-
 	g_main_loop_quit (loop);
 }
 
@@ -834,7 +831,7 @@ fill_output_access_point (gpointer data, gpointer user_data)
 	strength_str = g_strdup_printf ("%u", strength);
 	wpa_flags_str = ap_wpa_rsn_flags_to_string (wpa_flags);
 	rsn_flags_str = ap_wpa_rsn_flags_to_string (rsn_flags);
-	sig_bars = nm_utils_wifi_strength_bars (strength);
+	sig_bars = nmc_wifi_strength_bars (strength);
 
 	security_str = g_string_new (NULL);
 
diff --git a/clients/cli/general.c b/clients/cli/general.c
index 7ac6b22c..647ee5fc 100644
--- a/clients/cli/general.c
+++ b/clients/cli/general.c
@@ -175,6 +175,7 @@ _metagen_general_status_get_fcn (const NMMetaEnvironment *environment,
                                  NMMetaAccessorGetType get_type,
                                  NMMetaAccessorGetFlags get_flags,
                                  NMMetaAccessorGetOutFlags *out_flags,
+                                 gboolean *out_is_default,
                                  gpointer *out_to_free)
 {
 	NmCli *nmc = target;
@@ -282,6 +283,7 @@ _metagen_general_permissions_get_fcn (const NMMetaEnvironment *environment,
                                       NMMetaAccessorGetType get_type,
                                       NMMetaAccessorGetFlags get_flags,
                                       NMMetaAccessorGetOutFlags *out_flags,
+                                      gboolean *out_is_default,
                                       gpointer *out_to_free)
 {
 	NMClientPermission perm = GPOINTER_TO_UINT (target);
@@ -330,6 +332,7 @@ _metagen_general_logging_get_fcn (const NMMetaEnvironment *environment,
                                   NMMetaAccessorGetType get_type,
                                   NMMetaAccessorGetFlags get_flags,
                                   NMMetaAccessorGetOutFlags *out_flags,
+                                  gboolean *out_is_default,
                                   gpointer *out_to_free)
 {
 	NmCli *nmc = environment_user_data;
diff --git a/clients/cli/meson.build b/clients/cli/meson.build
new file mode 100644
index 00000000..65317a0a
--- /dev/null
+++ b/clients/cli/meson.build
@@ -0,0 +1,48 @@
+name = 'nmcli'
+
+# FIXME: nmcli-completion should be renamed to nmcli
+install_data(
+  'nmcli-completion',
+  install_dir: join_paths(nm_datadir, 'bash-completion', 'completions')
+)
+
+sources = files(
+  'agent.c',
+  'common.c',
+  'connections.c',
+  'devices.c',
+  'general.c',
+  'nmcli.c',
+  'polkit-agent.c',
+  'settings.c',
+  'utils.c'
+)
+
+deps = [
+  libnm_dep,
+  libnmc_base_dep,
+  libnmc_dep,
+  nm_core_dep,
+  readline_dep
+]
+
+cflags = clients_cflags + [
+  '-DG_LOG_DOMAIN="@0@"'.format(name),
+  '-DNMCLI_LOCALEDIR="@0@"'.format(nm_localedir)
+]
+
+if enable_polkit_agent
+  sources += nm_polkit_listener
+
+  deps += polkit_agent_dep
+endif
+
+executable(
+  name,
+  sources,
+  dependencies: deps,
+  c_args: cflags,
+  link_args: ldflags_linker_script_binary,
+  link_depends: linker_script_binary,
+  install: true
+)
diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c
index f5a66cdd..ec23ff43 100644
--- a/clients/cli/nmcli.c
+++ b/clients/cli/nmcli.c
@@ -36,8 +36,6 @@
 
 #include "nm-client-utils.h"
 
-#include "nm-utils/nm-hash-utils.h"
-
 #include "polkit-agent.h"
 #include "utils.h"
 #include "common.h"
@@ -186,6 +184,7 @@ usage (void)
 	g_printerr (_("Usage: nmcli [OPTIONS] OBJECT { COMMAND | help }\n"
 	              "\n"
 	              "OPTIONS\n"
+	              "  -o[verview]                                    overview mode (hide default values)\n"
 	              "  -t[erse]                                       terse output\n"
 	              "  -p[retty]                                      pretty output\n"
 	              "  -m[ode] tabular|multiline                      output mode\n"
@@ -297,9 +296,10 @@ process_command_line (NmCli *nmc, int argc, char **argv)
 			break;
 
 		if (argc == 1 && nmc->complete) {
-			nmc_complete_strings (argv[0], "--terse", "--pretty", "--mode", "--colors", "--escape",
-			                           "--fields", "--nocheck", "--get-values",
-			                            "--wait", "--version", "--help", NULL);
+			nmc_complete_strings (argv[0], "--terse", "--pretty", "--mode", "--overview",
+			                               "--colors", "--escape",
+			                               "--fields", "--nocheck", "--get-values",
+			                               "--wait", "--version", "--help", NULL);
 		}
 
 		if (argv[0][1] == '-' && argv[0][2] == '\0') {
@@ -308,7 +308,9 @@ process_command_line (NmCli *nmc, int argc, char **argv)
 			break;
 		}
 
-		if (matches_arg (nmc, &argc, &argv, "-terse", NULL)) {
+		if (matches_arg (nmc, &argc, &argv, "-overview", NULL)) {
+			nmc->nmc_config_mutable.overview = TRUE;
+		} else if (matches_arg (nmc, &argc, &argv, "-terse", NULL)) {
 			if (nmc->nmc_config.print_output == NMC_PRINT_TERSE) {
 				g_string_printf (nmc->return_text, _("Error: Option '--terse' is specified the second time."));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
@@ -417,6 +419,10 @@ process_command_line (NmCli *nmc, int argc, char **argv)
 		next_arg (nmc, &argc, &argv, NULL);
 	}
 
+	/* Ignore --overview when fields are set explicitly */
+	if (nmc->required_fields)
+		nmc->nmc_config_mutable.overview = FALSE;
+
 	/* Now run the requested command */
 	nmc_do_cmd (nmc, nmcli_cmds, *argv, argc, argv);
 
@@ -629,8 +635,6 @@ main (int argc, char *argv[])
 	textdomain (GETTEXT_PACKAGE);
 #endif
 
-	nm_g_type_init ();
-
 	/* Save terminal settings */
 	tcgetattr (STDIN_FILENO, &termios_orig);
 
diff --git a/clients/cli/nmcli.h b/clients/cli/nmcli.h
index 874bca21..0f3d29cd 100644
--- a/clients/cli/nmcli.h
+++ b/clients/cli/nmcli.h
@@ -20,17 +20,10 @@
 #ifndef NMC_NMCLI_H
 #define NMC_NMCLI_H
 
-#include "NetworkManager.h"
 #include "nm-secret-agent-old.h"
-
 #include "nm-meta-setting-desc.h"
 
-#if WITH_POLKIT_AGENT
-#include "nm-polkit-listener.h"
-#else
-/* polkit agent is not available; define fake NMPolkitListener */
-typedef gpointer NMPolkitListener;
-#endif
+struct _NMPolkitListener;
 
 typedef char *(*NmcCompEntryFunc) (const char *, int);
 
@@ -117,6 +110,7 @@ typedef struct _NmcConfig {
 	bool escape_values;                               /* Whether to escape ':' and '\' in terse tabular mode */
 	bool in_editor;                                   /* Whether running the editor - nmcli con edit' */
 	bool show_secrets;                                /* Whether to display secrets (both input and output): option '--show-secrets' */
+	bool overview;                                    /* Overview mode (hide default values) */
 } NmcConfig;
 
 typedef struct _NmcOutputData {
@@ -135,7 +129,7 @@ typedef struct _NmCli {
 
 	NMSecretAgentOld *secret_agent;                   /* Secret agent */
 	GHashTable *pwds_hash;                            /* Hash table with passwords in passwd-file */
-	NMPolkitListener *pk_listener ;                   /* polkit agent listener */
+	struct _NMPolkitListener *pk_listener;            /* polkit agent listener */
 
 	int should_wait;                                  /* Semaphore indicating whether nmcli should not end or not yet */
 	gboolean nowait_flag;                             /* '--nowait' option; used for passing to callbacks */
diff --git a/clients/cli/polkit-agent.c b/clients/cli/polkit-agent.c
index ecd58ba5..338f0b15 100644
--- a/clients/cli/polkit-agent.c
+++ b/clients/cli/polkit-agent.c
@@ -19,8 +19,6 @@
 
 #include "nm-default.h"
 
-#if WITH_POLKIT_AGENT
-
 #include "polkit-agent.h"
 
 #include <stdio.h>
@@ -29,17 +27,18 @@
 #include <unistd.h>
 
 #include "nm-polkit-listener.h"
-
 #include "common.h"
 
+#if WITH_POLKIT_AGENT
 static char *
-polkit_request (const char *request,
+polkit_request (NMPolkitListener *listener,
+                const char *request,
                 const char *action_id,
                 const char *message,
                 const char *icon_name,
                 const char *user,
                 gboolean echo_on,
-		gpointer user_data)
+                gpointer user_data)
 {
 	char *response, *tmp, *p;
 
@@ -62,28 +61,42 @@ polkit_request (const char *request,
 }
 
 static void
-polkit_show_info (const char *text)
+polkit_show_info (NMPolkitListener *listener,
+                  const char *text,
+                  gpointer user_data)
 {
 	g_print (_("Authentication message: %s\n"), text);
 }
 
 static void
-polkit_show_error (const char *text)
+polkit_show_error (NMPolkitListener *listener,
+                   const char *text,
+                   gpointer user_data)
 {
 	g_print (_("Authentication error: %s\n"), text);
 }
 
 static void
-polkit_completed (gboolean gained_authorization)
+polkit_completed (NMPolkitListener *listener,
+                  gboolean gained_authorization,
+                  gpointer user_data)
 {
 	/* We don't print anything here. The outcome will be evident from
 	 * the operation result anyway. */
 }
+#endif
 
 gboolean
 nmc_polkit_agent_init (NmCli* nmc, gboolean for_session, GError **error)
 {
-	PolkitAgentListener *listener;
+#if WITH_POLKIT_AGENT
+	static const NMPolkitListenVtable vtable = {
+		.on_request = polkit_request,
+		.on_show_info = polkit_show_info,
+		.on_show_error = polkit_show_error,
+		.on_completed = polkit_completed,
+	};
+	NMPolkitListener *listener;
 
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
@@ -91,24 +104,28 @@ nmc_polkit_agent_init (NmCli* nmc, gboolean for_session, GError **error)
 	if (!listener)
 		return FALSE;
 
-	nm_polkit_listener_set_request_callback (NM_POLKIT_LISTENER (listener), polkit_request, nmc);
-	nm_polkit_listener_set_show_info_callback (NM_POLKIT_LISTENER (listener), polkit_show_info);
-	nm_polkit_listener_set_show_error_callback (NM_POLKIT_LISTENER (listener), polkit_show_error);
-	nm_polkit_listener_set_completed_callback (NM_POLKIT_LISTENER (listener), polkit_completed);
+	nm_polkit_listener_set_vtable (listener, &vtable, nmc);
 
-	nmc->pk_listener = NM_POLKIT_LISTENER (listener);
+	nmc->pk_listener = listener;
+#endif
 	return TRUE;
 }
 
 void
 nmc_polkit_agent_fini (NmCli* nmc)
 {
-	g_clear_object (&nmc->pk_listener);
+#if WITH_POLKIT_AGENT
+	if (nmc->pk_listener) {
+		nm_polkit_listener_set_vtable (nmc->pk_listener, NULL, NULL);
+		g_clear_object (&nmc->pk_listener);
+	}
+#endif
 }
 
 gboolean
 nmc_start_polkit_agent_start_try (NmCli *nmc)
 {
+#if WITH_POLKIT_AGENT
 	GError *error = NULL;
 
 	/* We don't register polkit agent at all when running non-interactively */
@@ -121,30 +138,6 @@ nmc_start_polkit_agent_start_try (NmCli *nmc)
 		g_error_free (error);
 		return FALSE;
 	}
+#endif
 	return TRUE;
 }
-
-#else
-/* polkit agent is not avalable; implement stub functions. */
-
-#include "nmcli.h"
-#include "polkit-agent.h"
-
-gboolean
-nmc_polkit_agent_init (NmCli* nmc, gboolean for_session, GError **error)
-{
-	return TRUE;
-}
-
-void
-nmc_polkit_agent_fini (NmCli* nmc)
-{
-}
-
-gboolean
-nmc_start_polkit_agent_start_try (NmCli *nmc)
-{
-	return TRUE;
-}
-
-#endif /* #if WITH_POLKIT_AGENT */
diff --git a/clients/cli/settings.c b/clients/cli/settings.c
index 69275aad..5c3deead 100644
--- a/clients/cli/settings.c
+++ b/clients/cli/settings.c
@@ -313,16 +313,18 @@ _set_fcn_precheck_connection_secondaries (const char *value,
 {
 	const GPtrArray *connections;
 	NMConnection *con;
+	gs_free const char **strv0 = NULL;
 	gs_strfreev char **strv = NULL;
 	char **iter;
-	gboolean modified;
+	gboolean modified = FALSE;
 
-	strv = nmc_strsplit_set (value, " \t,", 0);
-	if (!strv)
+	strv0 = nm_utils_strsplit_set (value, " \t,");
+	if (!strv0)
 		return TRUE;
 
 	connections = nm_client_get_connections (nm_cli.client);
 
+	strv = g_strdupv ((char **) strv0);
 	for (iter = strv; *iter; iter++) {
 		if (nm_utils_is_uuid (*iter)) {
 			con = nmc_find_connection (connections, "uuid", *iter, NULL, FALSE);
@@ -472,6 +474,7 @@ get_property_val (NMSetting *setting, const char *prop, NMMetaAccessorGetType ge
 			                                               get_type,
 			                                               show_secrets ? NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS : 0,
 			                                               &out_flags,
+			                                               NULL,
 			                                               (gpointer *) &to_free);
 			nm_assert (!out_flags);
 			return to_free ?: g_strdup (value);
diff --git a/clients/cli/utils.c b/clients/cli/utils.c
index f20e24ce..71fdcf30 100644
--- a/clients/cli/utils.c
+++ b/clients/cli/utils.c
@@ -75,6 +75,7 @@ _meta_type_nmc_generic_info_get_fcn (const NMMetaAbstractInfo *abstract_info,
                                      NMMetaAccessorGetType get_type,
                                      NMMetaAccessorGetFlags get_flags,
                                      NMMetaAccessorGetOutFlags *out_flags,
+                                     gboolean *out_is_default,
                                      gpointer *out_to_free)
 {
 	const NmcMetaGenericInfo *info = (const NmcMetaGenericInfo *) abstract_info;
@@ -97,6 +98,7 @@ _meta_type_nmc_generic_info_get_fcn (const NMMetaAbstractInfo *abstract_info,
 		                      get_type,
 		                      get_flags,
 		                      out_flags,
+		                      out_is_default,
 		                      out_to_free);
 	}
 
@@ -524,7 +526,7 @@ nmc_count_color_escape_chars (const char *start, const char *end)
 			inside = TRUE;
 		if (inside)
 			num++;
-		if (*start == 'm') 
+		if (*start == 'm')
 			inside = FALSE;
 		start++;
 	}
@@ -603,9 +605,14 @@ int
 nmc_string_to_arg_array (const char *line, const char *delim, gboolean unquote,
                          char ***argv, int *argc)
 {
+	gs_free const char **arr0 = NULL;
 	char **arr;
 
-	arr = nmc_strsplit_set (line ? line : "", delim ? delim : " \t", 0);
+	arr0 = nm_utils_strsplit_set (line ?: "", delim ?: " \t");
+	if (!arr0)
+		arr = g_new0 (char *, 1);
+	else
+		arr = g_strdupv ((char **) arr0);
 
 	if (unquote) {
 		int i = 0;
@@ -613,7 +620,7 @@ nmc_string_to_arg_array (const char *line, const char *delim, gboolean unquote,
 		size_t l;
 		const char *quotes = "\"'";
 
-		while (arr && arr[i]) {
+		while (arr[i]) {
 			s = arr[i];
 			l = strlen (s);
 			if (l >= 2) {
@@ -628,7 +635,6 @@ nmc_string_to_arg_array (const char *line, const char *delim, gboolean unquote,
 
 	*argv = arr;
 	*argc = g_strv_length (arr);
-
 	return 0;
 }
 
@@ -998,6 +1004,7 @@ typedef struct {
 	const PrintDataCol *col;
 	const char *title;
 	bool title_to_free:1;
+	bool skip:1;
 	int width;
 } PrintDataHeaderCell;
 
@@ -1096,6 +1103,7 @@ _print_fill (const NmcConfig *nmc_config,
 
 		header_cell->col_idx = col_idx;
 		header_cell->col = col;
+		header_cell->skip = FALSE;
 
 		header_cell->title = nm_meta_abstract_info_get_name (info, TRUE);
 		if (   nmc_config->multiline_output
@@ -1130,10 +1138,11 @@ _print_fill (const NmcConfig *nmc_config,
 		for (i_col = 0; i_col < header_row->len; i_col++) {
 			char *to_free = NULL;
 			PrintDataCell *cell = &cells_line[i_col];
-			const PrintDataHeaderCell *header_cell;
+			PrintDataHeaderCell *header_cell;
 			const NMMetaAbstractInfo *info;
 			NMMetaAccessorGetOutFlags text_out_flags, color_out_flags;
 			gconstpointer value;
+			gboolean is_default;
 
 			header_cell = &g_array_index (header_row, PrintDataHeaderCell, i_col);
 			info = header_cell->col->selection_item->info;
@@ -1148,7 +1157,11 @@ _print_fill (const NmcConfig *nmc_config,
 			                                   text_get_type,
 			                                   text_get_flags,
 			                                   &text_out_flags,
+			                                   &is_default,
 			                                   (gpointer *) &to_free);
+
+			header_cell->skip = nmc_config->overview && is_default;
+
 			if (NM_FLAGS_HAS (text_out_flags, NM_META_ACCESSOR_GET_OUT_FLAGS_STRV)) {
 				if (value) {
 					if (nmc_config->multiline_output) {
@@ -1174,6 +1187,7 @@ _print_fill (const NmcConfig *nmc_config,
 			                                                      NM_META_ACCESSOR_GET_TYPE_TERMFORMAT,
 			                                                      NM_META_ACCESSOR_GET_FLAGS_NONE,
 			                                                      &color_out_flags,
+			                                                      NULL,
 			                                                      NULL),
 			                           &cell->term_color,
 			                           &cell->term_format);
@@ -1231,6 +1245,9 @@ _print_skip_column (const NmcConfig *nmc_config,
 	selection_item = header_cell->col->selection_item;
 	info = selection_item->info;
 
+	if (header_cell->skip)
+		return TRUE;
+
 	if (nmc_config->multiline_output) {
 		if (info->meta_type == &nm_meta_type_setting_info_editor) {
 			/* we skip the "name" entry for the setting in multiline output. */
diff --git a/clients/cli/utils.h b/clients/cli/utils.h
index ffc5b6f3..c92c4e2e 100644
--- a/clients/cli/utils.h
+++ b/clients/cli/utils.h
@@ -53,7 +53,6 @@ int nmc_string_to_arg_array (const char *line, const char *delim, gboolean unquo
                              char ***argv, int *argc);
 const char *nmc_string_is_valid (const char *input, const char **allowed, GError **error);
 char * nmc_util_strv_for_display (const char *const*strv, gboolean brackets);
-char **nmc_strsplit_set (const char *str, const char *delimiter, int max_tokens);
 int nmc_string_screen_width (const char *start, const char *end);
 void set_val_str  (NmcOutputField fields_array[], guint32 index, char *value);
 void set_val_strc (NmcOutputField fields_array[], guint32 index, const char *value);
@@ -151,6 +150,7 @@ struct _NmcMetaGenericInfo {
 	                          NMMetaAccessorGetType get_type,
 	                          NMMetaAccessorGetFlags get_flags,
 	                          NMMetaAccessorGetOutFlags *out_flags,
+	                          gboolean *out_is_default,
 	                          gpointer *out_to_free);
 };