diff options
| author | Michael Biebl <biebl@debian.org> | 2018-06-04 00:07:45 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2018-06-04 00:07:45 +0200 |
| commit | 04bc9e1cd3544445d883ad29ea108c1645c8e7b7 (patch) | |
| tree | d10c354b1b980ca8a7b9e48ec9019e8ed88bde2b /clients/cli | |
| parent | ee9c73a923909e23a649407be77e25235d769e25 (diff) | |
New upstream version 1.11.4 upstream/1.11.4
Diffstat (limited to 'clients/cli')
| -rw-r--r-- | clients/cli/agent.c | 3 | ||||
| -rw-r--r-- | clients/cli/common.c | 398 | ||||
| -rw-r--r-- | clients/cli/common.h | 14 | ||||
| -rw-r--r-- | clients/cli/connections.c | 1486 | ||||
| -rw-r--r-- | clients/cli/connections.h | 4 | ||||
| -rw-r--r-- | clients/cli/devices.c | 80 | ||||
| -rw-r--r-- | clients/cli/devices.h | 4 | ||||
| -rw-r--r-- | clients/cli/general.c | 115 | ||||
| -rw-r--r-- | clients/cli/meson.build | 49 | ||||
| -rw-r--r-- | clients/cli/nmcli.c | 430 | ||||
| -rw-r--r-- | clients/cli/nmcli.h | 34 | ||||
| -rw-r--r-- | clients/cli/polkit-agent.c | 73 | ||||
| -rw-r--r-- | clients/cli/settings.c | 13 | ||||
| -rw-r--r-- | clients/cli/utils.c | 228 | ||||
| -rw-r--r-- | clients/cli/utils.h | 85 |
15 files changed, 1612 insertions, 1404 deletions
diff --git a/clients/cli/agent.c b/clients/cli/agent.c index 488b16f4..bbfe47fb 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) @@ -136,7 +136,6 @@ secrets_requested (NMSecretAgentSimple *agent, nm_secret_agent_simple_response (agent, request_id, NULL); } - static NMCResultCode do_agent_secret (NmCli *nmc, int argc, char **argv) { diff --git a/clients/cli/common.c b/clients/cli/common.c index 0f5aea57..e566de47 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 - 2018 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" @@ -102,24 +100,19 @@ _ip_config_get_routes (NMIPConfig *cfg) } static gconstpointer -_metagen_ip4_config_get_fcn (const NMMetaEnvironment *environment, - gpointer environment_user_data, - const NmcMetaGenericInfo *info, - gpointer target, - NMMetaAccessorGetType get_type, - NMMetaAccessorGetFlags get_flags, - NMMetaAccessorGetOutFlags *out_flags, - gpointer *out_to_free) +_metagen_ip4_config_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) { NMIPConfig *cfg4 = target; GPtrArray *ptr_array; 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); + NMC_HANDLE_COLOR (NM_META_COLOR_NONE); + NM_SET_OUT (out_is_default, TRUE); switch (info->info_type) { case NMC_GENERIC_INFO_TYPE_IP4_CONFIG_ADDRESS: @@ -140,7 +133,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,34 +163,31 @@ _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; } static gconstpointer -_metagen_ip6_config_get_fcn (const NMMetaEnvironment *environment, - gpointer environment_user_data, - const NmcMetaGenericInfo *info, - gpointer target, - NMMetaAccessorGetType get_type, - NMMetaAccessorGetFlags get_flags, - NMMetaAccessorGetOutFlags *out_flags, - gpointer *out_to_free) +_metagen_ip6_config_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) { NMIPConfig *cfg6 = target; GPtrArray *ptr_array; 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); + NMC_HANDLE_COLOR (NM_META_COLOR_NONE); + NM_SET_OUT (out_is_default, TRUE); switch (info->info_type) { case NMC_GENERIC_INFO_TYPE_IP6_CONFIG_ADDRESS: @@ -216,7 +208,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 +233,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; @@ -259,11 +255,6 @@ const NmcMetaGenericInfo *const metagen_ip4_config[_NMC_GENERIC_INFO_TYPE_IP4_CO _METAGEN_IP4_CONFIG (NMC_GENERIC_INFO_TYPE_IP4_CONFIG_WINS, "WINS"), }; -static const NmcMetaGenericInfo *const metagen_ip4_config_group[] = { - NMC_META_GENERIC_WITH_NESTED ("IP4", metagen_ip4_config, .name_header = N_("GROUP")), - NULL, -}; - const NmcMetaGenericInfo *const metagen_ip6_config[_NMC_GENERIC_INFO_TYPE_IP6_CONFIG_NUM + 1] = { #define _METAGEN_IP6_CONFIG(type, name) \ [type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_ip6_config_get_fcn) @@ -274,14 +265,9 @@ const NmcMetaGenericInfo *const metagen_ip6_config[_NMC_GENERIC_INFO_TYPE_IP6_CO _METAGEN_IP6_CONFIG (NMC_GENERIC_INFO_TYPE_IP6_CONFIG_DOMAIN, "DOMAIN"), }; -static const NmcMetaGenericInfo *const metagen_ip6_config_group[] = { - NMC_META_GENERIC_WITH_NESTED ("IP6", metagen_ip6_config, .name_header = N_("GROUP")), - NULL, -}; - /*****************************************************************************/ -const NmcMetaGenericInfo *const nmc_fields_dhcp4_config[] = { +const NmcMetaGenericInfo *const nmc_fields_dhcp_config[] = { NMC_META_GENERIC ("GROUP"), /* 0 */ NMC_META_GENERIC ("OPTION"), /* 1 */ NULL, @@ -297,12 +283,6 @@ const NmcMetaGenericInfo *const nmc_fields_ip6_config[] = { NULL, }; -const NmcMetaGenericInfo *const nmc_fields_dhcp6_config[] = { - NMC_META_GENERIC ("GROUP"), /* 0 */ - NMC_META_GENERIC ("OPTION"), /* 1 */ - NULL, -}; - gboolean print_ip4_config (NMIPConfig *cfg4, const NmcConfig *nmc_config, @@ -320,7 +300,7 @@ print_ip4_config (NMIPConfig *cfg4, if (!nmc_print (nmc_config, (gpointer[]) { cfg4, NULL }, NULL, - (const NMMetaAbstractInfo *const*) metagen_ip4_config_group, + NMC_META_GENERIC_GROUP ("IP4", metagen_ip4_config, N_("GROUP")), field_str, &error)) { return FALSE; @@ -346,7 +326,7 @@ print_ip6_config (NMIPConfig *cfg6, if (!nmc_print (nmc_config, (gpointer[]) { cfg6, NULL }, NULL, - (const NMMetaAbstractInfo *const*) metagen_ip6_config_group, + NMC_META_GENERIC_GROUP ("IP6", metagen_ip6_config, N_("GROUP")), field_str, &error)) { return FALSE; @@ -355,82 +335,37 @@ print_ip6_config (NMIPConfig *cfg6, } gboolean -print_dhcp4_config (NMDhcpConfig *dhcp4, - const NmcConfig *nmc_config, - const char *group_prefix, - const char *one_field) +print_dhcp_config (NMDhcpConfig *dhcp, + const NmcConfig *nmc_config, + const char *group_prefix, + const char *one_field) { GHashTable *table; const NMMetaAbstractInfo *const*tmpl; NmcOutputField *arr; - if (dhcp4 == NULL) + if (dhcp == NULL) return FALSE; - table = nm_dhcp_config_get_options (dhcp4); + table = nm_dhcp_config_get_options (dhcp); if (table) { - GHashTableIter table_iter; - gpointer key, value; char **options_arr = NULL; - int i = 0; NMC_OUTPUT_DATA_DEFINE_SCOPED (out); + gs_free const char **keys = NULL; + guint i, nkeys; - tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_dhcp4_config; + tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_dhcp_config; out_indices = parse_output_fields (one_field, tmpl, FALSE, NULL, NULL); arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_FIELD_NAMES); g_ptr_array_add (out.output_data, arr); - options_arr = g_new (char *, g_hash_table_size (table) + 1); - g_hash_table_iter_init (&table_iter, table); - while (g_hash_table_iter_next (&table_iter, &key, &value)) - options_arr[i++] = g_strdup_printf ("%s = %s", (char *) key, (char *) value); - options_arr[i] = NULL; + keys = (const char **) g_hash_table_get_keys_as_array (table, &nkeys); + nm_utils_strv_sort (keys, nkeys); - arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_SECTION_PREFIX); - set_val_strc (arr, 0, group_prefix); - set_val_arr (arr, 1, options_arr); - g_ptr_array_add (out.output_data, arr); - - print_data_prepare_width (out.output_data); - print_data (nmc_config, out_indices, NULL, 0, &out); - - return TRUE; - } - return FALSE; -} - -gboolean -print_dhcp6_config (NMDhcpConfig *dhcp6, - const NmcConfig *nmc_config, - const char *group_prefix, - const char *one_field) -{ - GHashTable *table; - const NMMetaAbstractInfo *const*tmpl; - NmcOutputField *arr; - - if (dhcp6 == NULL) - return FALSE; - - table = nm_dhcp_config_get_options (dhcp6); - if (table) { - GHashTableIter table_iter; - gpointer key, value; - char **options_arr = NULL; - int i = 0; - NMC_OUTPUT_DATA_DEFINE_SCOPED (out); - - tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_dhcp6_config; - out_indices = parse_output_fields (one_field, - tmpl, FALSE, NULL, NULL); - arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_FIELD_NAMES); - g_ptr_array_add (out.output_data, arr); - - options_arr = g_new (char *, g_hash_table_size (table) + 1); - g_hash_table_iter_init (&table_iter, table); - while (g_hash_table_iter_next (&table_iter, &key, &value)) - options_arr[i++] = g_strdup_printf ("%s = %s", (char *) key, (char *) value); + options_arr = g_new (char *, nkeys + 1); + for (i = 0; i < nkeys; i++) + options_arr[i] = g_strdup_printf ("%s = %s", keys[i], (const char *) g_hash_table_lookup (table, keys[i])); options_arr[i] = NULL; arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_SECTION_PREFIX); @@ -451,8 +386,11 @@ print_dhcp6_config (NMDhcpConfig *dhcp6, * @connections: array of NMConnections to search in * @filter_type: "id", "uuid", "path" or %NULL * @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). + * @out_result: if not NULL, attach all matching connection to this + * list. If necessary, a new array will be allocated. If the array + * already contains a connection, it will not be added a second time. + * All object are referenced by the array. If the function allocates + * a new array, it will set the free function to g_object_unref. * @complete: print possible completions * * Find a connection in @list according to @filter_val. @filter_type determines @@ -467,64 +405,153 @@ NMConnection * nmc_find_connection (const GPtrArray *connections, const char *filter_type, const char *filter_val, - int *start, + GPtrArray **out_result, gboolean complete) { NMConnection *connection; - NMConnection *found = NULL; - int i; - const char *id; - const char *uuid; - const char *path, *path_num; + NMConnection *best_candidate = NULL; + GPtrArray *result = out_result ? *out_result : NULL; + guint i, j; - for (i = start ? *start : 0; i < connections->len; i++) { - connection = NM_CONNECTION (connections->pdata[i]); + nm_assert (connections); + nm_assert (filter_val); - id = nm_connection_get_id (connection); - uuid = nm_connection_get_uuid (connection); - path = nm_connection_get_path (connection); - path_num = path ? strrchr (path, '/') + 1 : NULL; + for (i = 0; i < connections->len; i++) { + const char *v, *v_num; + + connection = NM_CONNECTION (connections->pdata[i]); /* When filter_type is NULL, compare connection ID (filter_val) * against all types. Otherwise, only compare against the specific * 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) { + if (NM_IN_STRSET (filter_type, NULL, "id")) { + v = nm_connection_get_id (connection); if (complete) - nmc_complete_strings (filter_val, id, NULL); - if (strcmp (filter_val, id) == 0) + nmc_complete_strings (filter_val, v, NULL); + if (nm_streq0 (filter_val, v)) goto found; } - if (!filter_type || strcmp (filter_type, "uuid") == 0) { + if (NM_IN_STRSET (filter_type, NULL, "uuid")) { + v = nm_connection_get_uuid (connection); if (complete && (filter_type || *filter_val)) - nmc_complete_strings (filter_val, uuid, NULL); - if (strcmp (filter_val, uuid) == 0) + nmc_complete_strings (filter_val, v, NULL); + if (nm_streq0 (filter_val, v)) goto found; } - if (!filter_type || strcmp (filter_type, "path") == 0) { + if (NM_IN_STRSET (filter_type, NULL, "path")) { + v = nm_connection_get_path (connection); + v_num = nm_utils_dbus_path_get_last_component (v); 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)) + nmc_complete_strings (filter_val, v, filter_type ? v_num : NULL, NULL); + if ( nm_streq0 (filter_val, v) + || (filter_type && nm_streq0 (filter_val, v_num))) goto found; } continue; found: - if (!start) + if (!out_result) return connection; - if (found) { - *start = i; - return found; + if (!best_candidate) + best_candidate = connection; + if (!result) + result = g_ptr_array_new_with_free_func (g_object_unref); + for (j = 0; j < result->len; j++) { + if (connection == result->pdata[j]) + break; + } + if (j == result->len) + g_ptr_array_add (result, g_object_ref (connection)); + } + + NM_SET_OUT (out_result, result); + return best_candidate; +} + +NMActiveConnection * +nmc_find_active_connection (const GPtrArray *active_cons, + const char *filter_type, + const char *filter_val, + GPtrArray **out_result, + gboolean complete) +{ + guint i, j; + NMActiveConnection *best_candidate = NULL; + GPtrArray *result = out_result ? *out_result : NULL; + + nm_assert (filter_val); + + for (i = 0; i < active_cons->len; i++) { + NMRemoteConnection *con; + NMActiveConnection *candidate = g_ptr_array_index (active_cons, i); + const char *v, *v_num; + + con = nm_active_connection_get_connection (candidate); + + /* When filter_type is NULL, compare connection ID (filter_val) + * against all types. Otherwise, only compare against the specific + * type. If 'path' or 'apath' filter types are specified, comparison + * against numeric index (in addition to the whole path) is allowed. + */ + if (NM_IN_STRSET (filter_type, NULL, "id")) { + v = nm_active_connection_get_id (candidate); + if (complete) + nmc_complete_strings (filter_val, v, NULL); + if (nm_streq0 (filter_val, v)) + goto found; + } + + if (NM_IN_STRSET (filter_type, NULL, "uuid")) { + v = nm_active_connection_get_uuid (candidate); + if (complete && (filter_type || *filter_val)) + nmc_complete_strings (filter_val, v, NULL); + if (nm_streq0 (filter_val, v)) + goto found; + } + + if (NM_IN_STRSET (filter_type, NULL, "path")) { + v = con ? nm_connection_get_path (NM_CONNECTION (con)) : NULL; + v_num = nm_utils_dbus_path_get_last_component (v); + if (complete && (filter_type || *filter_val)) + nmc_complete_strings (filter_val, v, filter_type ? v_num : NULL, NULL); + if ( nm_streq0 (filter_val, v) + || (filter_type && nm_streq0 (filter_val, v_num))) + goto found; + } + + if (NM_IN_STRSET (filter_type, NULL, "apath")) { + v = nm_object_get_path (NM_OBJECT (candidate)); + v_num = nm_utils_dbus_path_get_last_component (v); + if (complete && (filter_type || *filter_val)) + nmc_complete_strings (filter_val, v, filter_type ? v_num : NULL, NULL); + if ( nm_streq0 (filter_val, v) + || (filter_type && nm_streq0 (filter_val, v_num))) + goto found; + } + + continue; + +found: + if (!out_result) + return candidate; + if (!best_candidate) + best_candidate = candidate; + if (!result) + result = g_ptr_array_new_with_free_func (g_object_unref); + for (j = 0; j < result->len; j++) { + if (candidate == result->pdata[j]) + break; } - found = connection; + if (j == result->len) + g_ptr_array_add (result, g_object_ref (candidate)); } - if (start) - *start = 0; - return found; + NM_SET_OUT (out_result, result); + return best_candidate; } static gboolean @@ -532,10 +559,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 +574,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 +597,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 +648,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 +664,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 +675,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 +908,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 +944,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 +1264,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/common.h b/clients/cli/common.h index 354b2a5f..8f4e47c2 100644 --- a/clients/cli/common.h +++ b/clients/cli/common.h @@ -27,15 +27,20 @@ gboolean print_ip4_config (NMIPConfig *cfg4, const NmcConfig *nmc_config, const char *one_field); gboolean print_ip6_config (NMIPConfig *cfg6, const NmcConfig *nmc_config, const char *group_prefix, const char *one_field); -gboolean print_dhcp4_config (NMDhcpConfig *dhcp4, const NmcConfig *nmc_config, const char *group_prefix, const char *one_field); -gboolean print_dhcp6_config (NMDhcpConfig *dhcp6, const NmcConfig *nmc_config, const char *group_prefix, const char *one_field); +gboolean print_dhcp_config (NMDhcpConfig *dhcp, const NmcConfig *nmc_config, const char *group_prefix, const char *one_field); NMConnection *nmc_find_connection (const GPtrArray *connections, const char *filter_type, const char *filter_val, - int *start, + GPtrArray **out_result, gboolean complete); +NMActiveConnection *nmc_find_active_connection (const GPtrArray *active_cons, + const char *filter_type, + const char *filter_val, + GPtrArray **out_result, + gboolean complete); + void nmc_secrets_requested (NMSecretAgentSimple *agent, const char *request_id, const char *title, @@ -78,8 +83,7 @@ void nmc_complete_bool (const char *prefix); const char *nmc_error_get_simple_message (GError *error); extern const NmcMetaGenericInfo *const metagen_ip4_config[]; -extern const NmcMetaGenericInfo *const nmc_fields_dhcp4_config[]; extern const NmcMetaGenericInfo *const nmc_fields_ip6_config[]; -extern const NmcMetaGenericInfo *const nmc_fields_dhcp6_config[]; +extern const NmcMetaGenericInfo *const nmc_fields_dhcp_config[]; #endif /* NMC_COMMON_H */ diff --git a/clients/cli/connections.c b/clients/cli/connections.c index e0f55c53..a4f129b6 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -14,7 +14,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2010 - 2017 Red Hat, Inc. + * Copyright 2010 - 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -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" @@ -78,6 +76,82 @@ struct _OptionInfo { /*****************************************************************************/ +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (active_connection_state_to_string, NMActiveConnectionState, + NM_UTILS_LOOKUP_DEFAULT (N_("unknown")), + NM_UTILS_LOOKUP_ITEM (NM_ACTIVE_CONNECTION_STATE_ACTIVATING, N_("activating")), + NM_UTILS_LOOKUP_ITEM (NM_ACTIVE_CONNECTION_STATE_ACTIVATED, N_("activated")), + NM_UTILS_LOOKUP_ITEM (NM_ACTIVE_CONNECTION_STATE_DEACTIVATING, N_("deactivating")), + NM_UTILS_LOOKUP_ITEM (NM_ACTIVE_CONNECTION_STATE_DEACTIVATED, N_("deactivated")), + NM_UTILS_LOOKUP_ITEM_IGNORE (NM_ACTIVE_CONNECTION_STATE_UNKNOWN), +) + +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (vpn_connection_state_to_string, NMVpnConnectionState, + NM_UTILS_LOOKUP_DEFAULT (N_("unknown")), + NM_UTILS_LOOKUP_ITEM (NM_VPN_CONNECTION_STATE_PREPARE, N_("VPN connecting (prepare)")), + NM_UTILS_LOOKUP_ITEM (NM_VPN_CONNECTION_STATE_NEED_AUTH, N_("VPN connecting (need authentication)")), + NM_UTILS_LOOKUP_ITEM (NM_VPN_CONNECTION_STATE_CONNECT, N_("VPN connecting")), + NM_UTILS_LOOKUP_ITEM (NM_VPN_CONNECTION_STATE_IP_CONFIG_GET, N_("VPN connecting (getting IP configuration)")), + NM_UTILS_LOOKUP_ITEM (NM_VPN_CONNECTION_STATE_ACTIVATED, N_("VPN connected")), + NM_UTILS_LOOKUP_ITEM (NM_VPN_CONNECTION_STATE_FAILED, N_("VPN connection failed")), + NM_UTILS_LOOKUP_ITEM (NM_VPN_CONNECTION_STATE_DISCONNECTED, N_("VPN disconnected")), + NM_UTILS_LOOKUP_ITEM_IGNORE (NM_VPN_CONNECTION_STATE_UNKNOWN), +) + +/* Essentially a version of nm_setting_connection_get_connection_type() that + * prefers an alias instead of the settings name when in pretty print mode. + * That is so that we print "wifi" instead of "802-11-wireless" in "nmcli c". */ +static const char * +connection_type_pretty (const char *type, NMCPrintOutput print_output) +{ + const NMMetaSettingInfoEditor *editor; + int i; + + if (print_output == NMC_PRINT_TERSE) + return type; + + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + editor = &nm_meta_setting_infos_editor[i]; + if (strcmp (type, editor->general->setting_name) == 0) { + if (editor->alias) + return editor->alias; + break; + } + } + + return type; +} + +/* Caller has to free the returned string */ +static char * +get_ac_device_string (NMActiveConnection *active) +{ + GString *dev_str; + const GPtrArray *devices; + int i; + + if (!active) + return NULL; + + /* Get devices of the active connection */ + dev_str = g_string_new (NULL); + devices = nm_active_connection_get_devices (active); + for (i = 0; i < devices->len; i++) { + NMDevice *device = g_ptr_array_index (devices, i); + const char *dev_iface = nm_device_get_iface (device); + + if (dev_iface) { + g_string_append (dev_str, dev_iface); + g_string_append_c (dev_str, ','); + } + } + if (dev_str->len > 0) + g_string_truncate (dev_str, dev_str->len - 1); /* Cut off last ',' */ + + return g_string_free (dev_str, FALSE); +} + +/*****************************************************************************/ + const NmcMetaGenericInfo *const nmc_fields_con_show[] = { NMC_META_GENERIC ("NAME"), /* 0 */ NMC_META_GENERIC ("UUID"), /* 1 */ @@ -151,7 +225,6 @@ const NmcMetaGenericInfo *const nmc_fields_con_active_details_general[] = { // NM_SETTING_DUMMY_SETTING_NAME // NM_SETTING_WIMAX_SETTING_NAME - const NmcMetaGenericInfo *const nmc_fields_con_active_details_vpn[] = { NMC_META_GENERIC ("GROUP"), /* 0 */ NMC_META_GENERIC ("TYPE"), /* 1 */ @@ -166,9 +239,9 @@ const NmcMetaGenericInfo *const nmc_fields_con_active_details_vpn[] = { const NmcMetaGenericInfo *const nmc_fields_con_active_details_groups[] = { NMC_META_GENERIC_WITH_NESTED ("GENERAL", nmc_fields_con_active_details_general + 1), /* 0 */ NMC_META_GENERIC_WITH_NESTED ("IP4", metagen_ip4_config), /* 1 */ - NMC_META_GENERIC_WITH_NESTED ("DHCP4", nmc_fields_dhcp4_config + 1), /* 2 */ + NMC_META_GENERIC_WITH_NESTED ("DHCP4", nmc_fields_dhcp_config + 1), /* 2 */ NMC_META_GENERIC_WITH_NESTED ("IP6", nmc_fields_ip6_config + 1), /* 3 */ - NMC_META_GENERIC_WITH_NESTED ("DHCP6", nmc_fields_dhcp6_config + 1), /* 4 */ + NMC_META_GENERIC_WITH_NESTED ("DHCP6", nmc_fields_dhcp_config + 1), /* 4 */ NMC_META_GENERIC_WITH_NESTED ("VPN", nmc_fields_con_active_details_vpn + 1), /* 5 */ NULL, }; @@ -189,7 +262,10 @@ typedef struct { NMSetting *setting; const char *property; } TabCompletionInfo; -static TabCompletionInfo nmc_tab_completion = {NULL, NULL, NULL, NULL}; + +static TabCompletionInfo nmc_tab_completion; + +/*****************************************************************************/ static void usage (void) @@ -505,12 +581,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); } @@ -523,97 +595,38 @@ construct_header_name (const char *base, const char *spec) return g_strdup_printf ("%s (%s)", base, spec); } -static const char * -active_connection_state_to_string (NMActiveConnectionState state) -{ - switch (state) { - case NM_ACTIVE_CONNECTION_STATE_ACTIVATING: - return _("activating"); - case NM_ACTIVE_CONNECTION_STATE_ACTIVATED: - return _("activated"); - case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING: - return _("deactivating"); - case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED: - return _("deactivated"); - case NM_ACTIVE_CONNECTION_STATE_UNKNOWN: - default: - return _("unknown"); - } -} - -static const char * -vpn_connection_state_to_string (NMVpnConnectionState state) -{ - switch (state) { - case NM_VPN_CONNECTION_STATE_PREPARE: - return _("VPN connecting (prepare)"); - case NM_VPN_CONNECTION_STATE_NEED_AUTH: - return _("VPN connecting (need authentication)"); - case NM_VPN_CONNECTION_STATE_CONNECT: - return _("VPN connecting"); - case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET: - return _("VPN connecting (getting IP configuration)"); - case NM_VPN_CONNECTION_STATE_ACTIVATED: - return _("VPN connected"); - case NM_VPN_CONNECTION_STATE_FAILED: - return _("VPN connection failed"); - case NM_VPN_CONNECTION_STATE_DISCONNECTED: - return _("VPN disconnected"); - default: - return _("unknown"); - } -} - -/* Caller has to free the returned string */ -static char * -get_ac_device_string (NMActiveConnection *active) -{ - GString *dev_str; - const GPtrArray *devices; - int i; - - if (!active) - return NULL; - - /* Get devices of the active connection */ - dev_str = g_string_new (NULL); - devices = nm_active_connection_get_devices (active); - for (i = 0; i < devices->len; i++) { - NMDevice *device = g_ptr_array_index (devices, i); - const char *dev_iface = nm_device_get_iface (device); - - if (dev_iface) { - g_string_append (dev_str, dev_iface); - g_string_append_c (dev_str, ','); - } - } - if (dev_str->len > 0) - g_string_truncate (dev_str, dev_str->len - 1); /* Cut off last ',' */ - - return g_string_free (dev_str, FALSE); -} - static NMActiveConnection * -get_ac_for_connection (const GPtrArray *active_cons, NMConnection *connection) +get_ac_for_connection (const GPtrArray *active_cons, NMConnection *connection, GPtrArray **out_result) { const char *con_path, *ac_con_path; - int i; - NMActiveConnection *ac = NULL; + guint i; + NMActiveConnection *best_candidate = NULL; + GPtrArray *result = out_result ? *out_result : NULL; - /* Is the connection active? */ con_path = nm_connection_get_path (connection); for (i = 0; i < active_cons->len; i++) { NMActiveConnection *candidate = g_ptr_array_index (active_cons, i); NMRemoteConnection *con; con = nm_active_connection_get_connection (candidate); - ac_con_path = con ? nm_connection_get_path (NM_CONNECTION (con)) : NULL; - if (!g_strcmp0 (ac_con_path, con_path)) { - ac = candidate; - break; + if (NM_CONNECTION (con) != connection) { + /* also compare the D-Bus paths. Why? I don't know. */ + ac_con_path = con ? nm_connection_get_path (NM_CONNECTION (con)) : NULL; + if (!nm_streq0 (ac_con_path, con_path)) + continue; } + + if (!out_result) + return candidate; + if (!best_candidate) + best_candidate = candidate; + if (!result) + result = g_ptr_array_new_with_free_func (g_object_unref); + g_ptr_array_add (result, g_object_ref (candidate)); } - return ac; + + NM_SET_OUT (out_result, result); + return best_candidate; } typedef struct { @@ -741,118 +754,17 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc) return TRUE; } -static NMActiveConnection * -find_active_connection (const GPtrArray *active_cons, - const GPtrArray *cons, - const char *filter_type, - const char *filter_val, - int *idx, - gboolean complete) -{ - int i; - int start = (idx && *idx > 0) ? *idx : 0; - const char *path, *a_path, *path_num, *a_path_num; - const char *id; - const char *uuid; - NMRemoteConnection *con; - NMActiveConnection *found = NULL; - - for (i = start; i < active_cons->len; i++) { - NMActiveConnection *candidate = g_ptr_array_index (active_cons, i); - - con = nm_active_connection_get_connection (candidate); - - id = nm_active_connection_get_id (candidate); - uuid = nm_active_connection_get_uuid (candidate); - path = con ? nm_connection_get_path (NM_CONNECTION (con)) : NULL; - path_num = path ? strrchr (path, '/') + 1 : NULL; - a_path = nm_object_get_path (NM_OBJECT (candidate)); - a_path_num = a_path ? strrchr (a_path, '/') + 1 : NULL; - - /* When filter_type is NULL, compare connection ID (filter_val) - * against all types. Otherwise, only compare against the specific - * 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) { - 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) - *idx = 0; - return found; -} - -void -nmc_active_connection_state_to_color (NMActiveConnectionState state, NMMetaTermColor *color) +NMMetaColor +nmc_active_connection_state_to_color (NMActiveConnectionState state) { - *color = NM_META_TERM_COLOR_NORMAL; - if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING) - *color = NM_META_TERM_COLOR_YELLOW; + return NM_META_COLOR_CONNECTION_ACTIVATING; else if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) - *color = NM_META_TERM_COLOR_GREEN; + return NM_META_COLOR_CONNECTION_ACTIVATED; else if (state > NM_ACTIVE_CONNECTION_STATE_ACTIVATED) - *color = NM_META_TERM_COLOR_RED; -} - -/* Essentially a version of nm_setting_connection_get_connection_type() that - * prefers an alias instead of the settings name when in pretty print mode. - * That is so that we print "wifi" instead of "802-11-wireless" in "nmcli c". */ -static const char * -connection_type_pretty (const char *type, NMCPrintOutput print_output) -{ - const NMMetaSettingInfoEditor *editor; - int i; - - if (print_output == NMC_PRINT_TERSE) - return type; - - for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { - editor = &nm_meta_setting_infos_editor[i]; - if (strcmp (type, editor->general->setting_name) == 0) { - if (editor->alias) - return editor->alias; - break; - } - } - - return type; + return NM_META_COLOR_CONNECTION_DISCONNECTING; + else + return NM_META_COLOR_CONNECTION_UNKNOWN; } static void @@ -871,19 +783,19 @@ fill_output_connection (NMConnection *connection, NMClient *client, NMCPrintOutp const char *ac_state = NULL; NMActiveConnectionState ac_state_int = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; char *ac_dev = NULL; - NMMetaTermColor color; + NMMetaColor color; s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); - ac = get_ac_for_connection (nm_client_get_active_connections (client), connection); + ac = get_ac_for_connection (nm_client_get_active_connections (client), connection, NULL); if (active_only && !ac) return; if (ac) { ac_path = nm_object_get_path (NM_OBJECT (ac)); ac_state_int = nm_active_connection_get_state (ac); - ac_state = active_connection_state_to_string (ac_state_int); + ac_state = gettext (active_connection_state_to_string (ac_state_int)); ac_dev = get_ac_device_string (ac); } @@ -900,7 +812,7 @@ fill_output_connection (NMConnection *connection, NMClient *client, NMCPrintOutp arr = nmc_dup_fields_array ((const NMMetaAbstractInfo *const*) nmc_fields_con_show, 0); /* Show active connections in color */ - nmc_active_connection_state_to_color (ac_state_int, &color); + color = nmc_active_connection_state_to_color (ac_state_int); set_val_color_all (arr, color); set_val_strc (arr, 0, nm_setting_connection_get_id (s_con)); @@ -951,7 +863,7 @@ fill_output_connection_for_invisible (NMActiveConnection *ac, NMCPrintOutput pri set_val_strc (arr, 12, ac_path); set_val_strc (arr, 13, NULL); - set_val_color_fmt_all (arr, NM_META_TERM_FORMAT_DIM); + set_val_color_all (arr, NM_META_COLOR_CONNECTION_INVISIBLE); g_ptr_array_add (output_data, arr); } @@ -978,7 +890,7 @@ fill_output_active_connection (NMActiveConnection *active, if (con) { con_path = nm_connection_get_path (NM_CONNECTION (con)); s_con = nm_connection_get_setting_connection (NM_CONNECTION (con)); - g_assert (s_con != NULL); + g_assert (s_con); con_zone = nm_setting_connection_get_zone (s_con); } @@ -1099,7 +1011,9 @@ static const gchar * get_vpn_data_item (NMConnection *connection, enum VpnDataItem vpn_data_item) { const char *key; - char *type = get_vpn_connection_type (connection); + gs_free char *type = NULL; + + type = get_vpn_connection_type (connection); switch (vpn_data_item) { case VPN_DATA_ITEM_GATEWAY: @@ -1112,7 +1026,6 @@ get_vpn_data_item (NMConnection *connection, enum VpnDataItem vpn_data_item) key = ""; break; } - g_free (type); return nm_setting_vpn_get_data_item (nm_connection_get_setting_vpn (connection), key); } @@ -1128,7 +1041,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 +1094,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); @@ -1211,7 +1122,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) gboolean b1 = FALSE; NMDhcpConfig *dhcp4 = nm_active_connection_get_dhcp4_config (acon); - b1 = print_dhcp4_config (dhcp4, &nmc->nmc_config, "DHCP4", group_fld); + b1 = print_dhcp_config (dhcp4, &nmc->nmc_config, "DHCP4", group_fld); was_output = was_output || b1; } @@ -1229,7 +1140,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) gboolean b1 = FALSE; NMDhcpConfig *dhcp6 = nm_active_connection_get_dhcp6_config (acon); - b1 = print_dhcp6_config (dhcp6, &nmc->nmc_config, "DHCP6", group_fld); + b1 = print_dhcp_config (dhcp6, &nmc->nmc_config, "DHCP6", group_fld); was_output = was_output || b1; } @@ -1250,7 +1161,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) con = NM_CONNECTION (nm_active_connection_get_connection (acon)); s_con = nm_connection_get_setting_connection (con); - g_assert (s_con != NULL); + g_assert (s_con); tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_vpn; out_indices = parse_output_fields (group_fld, @@ -1278,13 +1189,15 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) if (banner) banner_str = g_strescape (banner, ""); vpn_state = nm_vpn_connection_get_vpn_state (NM_VPN_CONNECTION (acon)); - vpn_state_str = g_strdup_printf ("%d - %s", vpn_state, vpn_connection_state_to_string (vpn_state)); + vpn_state_str = g_strdup_printf ("%d - %s", + vpn_state, + gettext (vpn_connection_state_to_string (vpn_state))); /* Add values */ arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_SECTION_PREFIX); set_val_strc (arr, 0, nmc_fields_con_active_details_groups[5]->name); set_val_str (arr, 1, type_str); - set_val_strc (arr, 2, username ? username : get_vpn_data_item (con, VPN_DATA_ITEM_USERNAME)); + set_val_strc (arr, 2, username ?: get_vpn_data_item (con, VPN_DATA_ITEM_USERNAME)); set_val_strc (arr, 3, get_vpn_data_item (con, VPN_DATA_ITEM_GATEWAY)); set_val_str (arr, 4, banner_str); set_val_str (arr, 5, vpn_state_str); @@ -1439,34 +1352,34 @@ typedef struct { static int compare_connections (gconstpointer a, gconstpointer b, gpointer user_data) { - NMConnection *ca = *(NMConnection **)a; - NMConnection *cb = *(NMConnection **)b; + NMConnection *ca = *(NMConnection **) a; + NMConnection *cb = *(NMConnection **) b; + const NmcSortInfo *info = user_data; NMActiveConnection *aca, *acb; - NmcSortInfo *info = (NmcSortInfo *) user_data; - GArray *default_order = NULL; - const GArray *order; - NmcSortOrder item; - int cmp = 0, i; + const NmcSortOrder *order_arr; + guint i, order_len; const char *tmp1, *tmp2; unsigned long tmp1_int, tmp2_int; - if (info->order ) - order = info->order; - else { - NmcSortOrder def[] = { NMC_SORT_ACTIVE, NMC_SORT_NAME, NMC_SORT_PATH }; - int num = G_N_ELEMENTS (def); - default_order = g_array_sized_new (FALSE, FALSE, sizeof (NmcSortOrder), num); - g_array_append_vals (default_order, def, num); - order = default_order; + if (info->order) { + order_arr = &g_array_index (info->order, NmcSortOrder, 0); + order_len = info->order->len; + } else { + static const NmcSortOrder def[] = { NMC_SORT_ACTIVE, NMC_SORT_NAME, NMC_SORT_PATH }; + + order_arr = def; + order_len = G_N_ELEMENTS (def); } - for (i = 0; i < order->len; i++) { - item = g_array_index (order, NmcSortOrder, i); + for (i = 0; i < order_len; i++) { + NmcSortOrder item = order_arr[i]; + int cmp = 0; + switch (item) { case NMC_SORT_ACTIVE: case NMC_SORT_ACTIVE_INV: - aca = get_ac_for_connection (nm_client_get_active_connections (info->nmc->client), ca); - acb = get_ac_for_connection (nm_client_get_active_connections (info->nmc->client), cb); + aca = get_ac_for_connection (nm_client_get_active_connections (info->nmc->client), ca, NULL); + acb = get_ac_for_connection (nm_client_get_active_connections (info->nmc->client), cb, NULL); cmp = (aca && !acb) ? -1 : (!aca && acb) ? 1 : 0; if (item == NMC_SORT_ACTIVE_INV) cmp = -(cmp); @@ -1502,12 +1415,10 @@ compare_connections (gconstpointer a, gconstpointer b, gpointer user_data) break; } if (cmp != 0) - goto end; + return cmp; } -end: - if (default_order) - g_array_unref (default_order); - return cmp; + + return 0; } static GPtrArray * @@ -1559,7 +1470,7 @@ get_invisible_active_connections (NmCli *nmc) GPtrArray *invisibles; int a, c; - g_return_val_if_fail (nmc != NULL, NULL); + g_return_val_if_fail (nmc, NULL); invisibles = g_ptr_array_new (); acons = nm_client_get_active_connections (nmc->client); @@ -1589,18 +1500,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,17 +1553,25 @@ parse_preferred_connection_order (const char *order, GError **error) 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) +get_connection (NmCli *nmc, + int *argc, + char ***argv, + const char **out_selector, + const char **out_value, + GPtrArray **out_result, + GError **error) { const GPtrArray *connections; NMConnection *connection = NULL; const char *selector = NULL; + NM_SET_OUT (out_selector, NULL); + NM_SET_OUT (out_value, NULL); + if (*argc == 0) { g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, _("No connection specified")); @@ -1662,45 +1581,46 @@ 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)--; } } + NM_SET_OUT (out_selector, selector); + NM_SET_OUT (out_value, **argv); + connections = nm_client_get_connections (nmc->client); - connection = nmc_find_connection (connections, selector, **argv, pos, + connection = nmc_find_connection (connections, selector, **argv, out_result, *argc == 1 && nmc->complete); if (!connection) { g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_NOT_FOUND, _("unknown connection '%s'"), **argv); } - /* If the caller wants multiple results (pos is set) and there are any, - * don't switch to next argument. - */ - if (!pos || !*pos) - next_arg (nmc, argc, argv, NULL); - + next_arg (nmc, argc, argv, NULL); return connection; } static NMCResultCode do_connections_show (NmCli *nmc, int argc, char **argv) { - GError *err = NULL; - char *profile_flds = NULL, *active_flds = NULL; + gs_free_error GError *err = NULL; + gs_free char *profile_flds = NULL; + gs_free char *active_flds = NULL; GPtrArray *invisibles, *sorted_cons; gboolean active_only = FALSE; - GArray *order = NULL; - int i, option; + gs_unref_array GArray *order = NULL; + guint i, j; + int option; /* check connection show options [--active] [--order <order spec>] */ while ((option = next_arg (nmc, &argc, &argv, "--active", "--order", NULL)) > 0) { @@ -1775,7 +1695,6 @@ do_connections_show (NmCli *nmc, int argc, char **argv) gboolean new_line = FALSE; gboolean without_fields = (nmc->required_fields == NULL); const GPtrArray *active_cons = nm_client_get_active_connections (nmc->client); - int pos = 0; /* multiline mode is default for 'connection show <ID>' */ if (!nmc->mode_specified) @@ -1784,8 +1703,8 @@ do_connections_show (NmCli *nmc, int argc, char **argv) /* Split required fields into the settings and active ones. */ if (!split_required_fields_for_con_show (nmc->required_fields, &profile_flds, &active_flds, &err)) goto finish; - g_free (nmc->required_fields); - nmc->required_fields = NULL; + + nm_clear_g_free (&nmc->required_fields); /* Before printing the connections check if we have a "--show-secret" * option after the connection ids */ @@ -1794,10 +1713,7 @@ do_connections_show (NmCli *nmc, int argc, char **argv) char **argv_cp = argv; do { - if ( nm_streq (*argv_cp, "id") - || nm_streq (*argv_cp, "uuid") - || nm_streq (*argv_cp, "path") - || nm_streq (*argv_cp, "apath")) { + if (NM_IN_STRSET (*argv_cp, "id", "uuid", "path", "apath")) { argc_cp--; argv_cp++; } @@ -1808,16 +1724,16 @@ do_connections_show (NmCli *nmc, int argc, char **argv) const GPtrArray *connections; gboolean res; NMConnection *con; - NMActiveConnection *acon = NULL; + gs_unref_object NMActiveConnection *explicit_acon = NULL; const char *selector = NULL; + gs_unref_ptrarray GPtrArray *found_cons = NULL; + gboolean explicit_acon_handled = FALSE; + guint i_found_cons; 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 - || strcmp (*argv, "apath") == 0) { + if (NM_IN_STRSET (*argv, "id", "uuid", "path", "apath")) { selector = *argv; argc--; argv++; @@ -1830,17 +1746,26 @@ do_connections_show (NmCli *nmc, int argc, char **argv) /* Try to find connection by id, uuid or path first */ connections = nm_client_get_connections (nmc->client); - con = nmc_find_connection (connections, selector, *argv, &pos, + con = nmc_find_connection (connections, selector, *argv, &found_cons, argc == 1 && nmc->complete); - if (!con && (!selector || strcmp (selector, "apath") == 0)) { + if ( !con + && NM_IN_STRSET (selector, NULL, "apath")) { /* Try apath too */ - acon = find_active_connection (active_cons, connections, "apath", *argv, NULL, - argc == 1 && nmc->complete); - if (acon) - con = NM_CONNECTION (nm_active_connection_get_connection (acon)); + explicit_acon = nmc_find_active_connection (active_cons, "apath", *argv, NULL, + argc == 1 && nmc->complete); + if (explicit_acon) { + if ( !selector + && !nm_streq0 (*argv, nm_object_get_path (NM_OBJECT (explicit_acon)))) { + /* we matched the apath based on the last component alone (note the full D-Bus path). + * That is how nmc_find_active_connection() works, if you pass in a selector. + * Reject it. */ + explicit_acon = NULL; + } + nm_g_object_ref (explicit_acon); + } } - if (!con && !acon) { + if (!con && !explicit_acon) { g_string_printf (nmc->return_text, _("Error: %s - no such connection profile."), *argv); nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; goto finish; @@ -1852,54 +1777,81 @@ do_connections_show (NmCli *nmc, int argc, char **argv) * may see only the active connection. */ - /* Filter only active connections */ - if (!acon) - acon = get_ac_for_connection (active_cons, con); - if (active_only && !acon) { - next_arg (nmc, &argc, &argv, NULL); - continue; - } - if (nmc->complete) { next_arg (nmc, &argc, &argv, NULL); continue; } - /* Show an empty line between connections */ - if (new_line) - g_print ("\n"); - - /* Show profile configuration */ - if (without_fields || profile_flds) { - if (con) { - nmc->required_fields = profile_flds; - if (nmc->nmc_config.show_secrets) - update_secrets_in_connection (NM_REMOTE_CONNECTION (con), con); - res = nmc_connection_profile_details (con, nmc); - nmc->required_fields = NULL; - if (!res) - goto finish; + explicit_acon_handled = FALSE; + i_found_cons = 0; + for (;;) { + gs_unref_ptrarray GPtrArray *found_acons = NULL; + + if (explicit_acon) { + if (explicit_acon_handled) + break; + explicit_acon_handled = TRUE; + /* the user referenced an "apath". In this case, we can only have at most one connection + * and one apath. */ + con = NM_CONNECTION (nm_active_connection_get_connection (explicit_acon)); + } else { + if (i_found_cons >= found_cons->len) + break; + con = found_cons->pdata[i_found_cons++]; + get_ac_for_connection (active_cons, con, &found_acons); } - } - /* If the profile is active, print also active details */ - if (without_fields || active_flds) { - if (acon) { - nmc->required_fields = active_flds; - res = nmc_active_connection_details (acon, nmc); - nmc->required_fields = NULL; - if (!res) - goto finish; + if (active_only && !explicit_acon && !found_acons) { + /* this connection is not interesting, we only print active ones. */ + continue; + } + + nm_assert (explicit_acon || con); + + if (new_line) + g_print ("\n"); + new_line = TRUE; + + if (without_fields || profile_flds) { + if (con) { + nmc->required_fields = profile_flds; + if (nmc->nmc_config.show_secrets) + update_secrets_in_connection (NM_REMOTE_CONNECTION (con), con); + res = nmc_connection_profile_details (con, nmc); + nmc->required_fields = NULL; + if (!res) + goto finish; + } + } + + if (without_fields || active_flds) { + guint l = explicit_acon ? 1 : (found_acons ? found_acons->len : 0); + + for (j = 0; j < l; j++) { + NMActiveConnection *acon; + + if (j > 0) { + /* if there are multiple active connections, separate them with newline. + * that is a bit odd, because we already separate connections with newlines, + * and commonly don't separate the connection from the first active connection. */ + g_print ("\n"); + } + + if (explicit_acon) + acon = explicit_acon; + else + acon = found_acons->pdata[j]; + + nmc->required_fields = active_flds; + res = nmc_active_connection_details (acon, nmc); + nmc->required_fields = NULL; + if (!res) + goto finish; + } } } - new_line = TRUE; - /* Take next argument. - * But for pos != NULL we have more connections of the same name, - * so process the same argument again. - */ - if (!pos) - next_arg (nmc, &argc, &argv, NULL); + next_arg (nmc, &argc, &argv, NULL); } } @@ -1907,12 +1859,7 @@ finish: if (err) { g_string_printf (nmc->return_text, _("Error: %s."), err->message); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - g_error_free (err); } - g_free (profile_flds); - g_free (active_flds); - if (order) - g_array_unref (order); return nmc->return_value; } @@ -1925,8 +1872,8 @@ get_default_active_connection (NmCli *nmc, NMDevice **device) const GPtrArray *connections; int i; - g_return_val_if_fail (nmc != NULL, NULL); - g_return_val_if_fail (device != NULL, NULL); + g_return_val_if_fail (nmc, NULL); + g_return_val_if_fail (device, NULL); g_return_val_if_fail (*device == NULL, NULL); connections = nm_client_get_active_connections (nmc->client); @@ -1984,10 +1931,10 @@ find_device_for_connection (NmCli *nmc, const char *con_type; int i, j; - g_return_val_if_fail (nmc != NULL, FALSE); + g_return_val_if_fail (nmc, FALSE); g_return_val_if_fail (iface || ap || nsp, FALSE); - g_return_val_if_fail (device != NULL && *device == NULL, FALSE); - g_return_val_if_fail (spec_object != NULL && *spec_object == NULL, FALSE); + g_return_val_if_fail (device && *device == NULL, FALSE); + g_return_val_if_fail (spec_object && *spec_object == NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); s_con = nm_connection_get_setting_connection (connection); @@ -2042,8 +1989,10 @@ find_device_for_connection (NmCli *nmc, } found_device = dev; - if (ap && !strcmp (con_type, NM_SETTING_WIRELESS_SETTING_NAME) && NM_IS_DEVICE_WIFI (dev)) { - char *bssid_up = g_ascii_strup (ap, -1); + if ( ap + && nm_streq (con_type, NM_SETTING_WIRELESS_SETTING_NAME) + && NM_IS_DEVICE_WIFI (dev)) { + gs_free char *bssid_up = g_ascii_strup (ap, -1); const GPtrArray *aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (dev)); found_device = NULL; /* Mark as not found; set to the device again later, only if AP matches */ @@ -2051,29 +2000,28 @@ find_device_for_connection (NmCli *nmc, NMAccessPoint *candidate_ap = g_ptr_array_index (aps, j); const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap); - if (!strcmp (bssid_up, candidate_bssid)) { + if (nm_streq0 (bssid_up, candidate_bssid)) { found_device = dev; *spec_object = nm_object_get_path (NM_OBJECT (candidate_ap)); break; } } - g_free (bssid_up); } - } - if (found_device) { - *device = found_device; - return TRUE; - } else { - if (iface) + if (!found_device) { + if (iface) { g_set_error (error, NMCLI_ERROR, 0, _("device '%s' not compatible with connection '%s'"), iface, nm_setting_connection_get_id (s_con)); - else + } else { g_set_error (error, NMCLI_ERROR, 0, _("no device found for connection '%s'"), nm_setting_connection_get_id (s_con)); + } return FALSE; } + + *device = found_device; + return TRUE; } } @@ -2295,48 +2243,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,25 +2295,15 @@ 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); } - - static gboolean nmc_activate_connection (NmCli *nmc, NMConnection *connection, @@ -2382,7 +2322,7 @@ nmc_activate_connection (NmCli *nmc, gboolean device_found; GError *local = NULL; - g_return_val_if_fail (nmc != NULL, FALSE); + g_return_val_if_fail (nmc, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (connection && (ifname || ap || nsp)) { @@ -2482,7 +2422,7 @@ do_connection_up (NmCli *nmc, int argc, char **argv) } if (argc > 0 && strcmp (*argv, "ifname") != 0) { - connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, &error); + connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, NULL, NULL, &error); if (!connection) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); return error->code; @@ -2561,20 +2501,108 @@ do_connection_up (NmCli *nmc, int argc, char **argv) return nmc->return_value; } +/*****************************************************************************/ + typedef struct { NmCli *nmc; - GSList *queue; + /* a list of object that is relevant for the callback. The object + * type differs, and depends on the type of callback. */ + GPtrArray *obj_list; guint timeout_id; GCancellable *cancellable; } ConnectionCbInfo; -static void connection_cb_info_finish (ConnectionCbInfo *info, - gpointer connection); +static void connection_removed_cb (NMClient *client, NMConnection *connection, ConnectionCbInfo *info); + +static void down_active_connection_state_cb (NMActiveConnection *active, + GParamSpec *pspec, + ConnectionCbInfo *info); + +static void +connection_cb_info_obj_list_destroy (ConnectionCbInfo *info, gpointer obj) +{ + nm_assert (info); + nm_assert (info->obj_list); + nm_assert (G_IS_OBJECT (obj)); + + g_signal_handlers_disconnect_by_func (obj, down_active_connection_state_cb, info); + g_object_unref (obj); +} + +static gssize +connection_cb_info_obj_list_idx (ConnectionCbInfo *info, gpointer obj) +{ + guint i; + + nm_assert (info); + nm_assert (info->obj_list); + nm_assert (G_IS_OBJECT (obj)); + + for (i = 0; i < info->obj_list->len; i++) { + if (info->obj_list->pdata[i] == obj) + return i; + } + return -1; +} + +static gpointer +connection_cb_info_obj_list_has (ConnectionCbInfo *info, gpointer obj) +{ + gssize idx; + + idx = connection_cb_info_obj_list_idx (info, obj); + if (idx >= 0) + return info->obj_list->pdata[idx]; + return NULL; +} + +static gpointer +connection_cb_info_obj_list_steal (ConnectionCbInfo *info, gpointer obj) +{ + gssize idx; + + idx = connection_cb_info_obj_list_idx (info, obj); + if (idx >= 0) { + g_ptr_array_remove_index (info->obj_list, idx); + return obj; + } + return NULL; +} + +static void +connection_cb_info_finish (ConnectionCbInfo *info, gpointer obj) +{ + if (obj) { + obj = connection_cb_info_obj_list_steal (info, obj); + if (obj) + connection_cb_info_obj_list_destroy (info, obj); + } else { + while (info->obj_list->len > 0) { + obj = info->obj_list->pdata[info->obj_list->len - 1]; + g_ptr_array_remove_index (info->obj_list, info->obj_list->len); + connection_cb_info_obj_list_destroy (info, obj); + } + } + + if (info->obj_list->len > 0) + return; + + nm_clear_g_source (&info->timeout_id); + nm_clear_g_cancellable (&info->cancellable); + + g_signal_handlers_disconnect_by_func (info->nmc->client, connection_removed_cb, info); + + g_slice_free (ConnectionCbInfo, info); + + quit (); +} + +/*****************************************************************************/ static void connection_removed_cb (NMClient *client, NMConnection *connection, ConnectionCbInfo *info) { - if (!g_slist_find (info->queue, connection)) + if (!connection_cb_info_obj_list_has (info, connection)) return; g_print (_("Connection '%s' (%s) successfully deleted.\n"), nm_connection_get_id (connection), @@ -2611,49 +2639,17 @@ connection_op_timeout_cb (gpointer user_data) return G_SOURCE_REMOVE; } -static void -destroy_queue_element (gpointer data) -{ - g_signal_handlers_disconnect_matched (data, G_SIGNAL_MATCH_FUNC, 0, 0, 0, - down_active_connection_state_cb, NULL); - g_object_unref (data); -} - -static void -connection_cb_info_finish (ConnectionCbInfo *info, gpointer connection) -{ - if (connection) { - info->queue = g_slist_remove (info->queue, connection); - g_object_unref (G_OBJECT (connection)); - } else { - g_slist_free_full (info->queue, destroy_queue_element); - info->queue = NULL; - } - - if (info->queue) - return; - - if (info->timeout_id) - g_source_remove (info->timeout_id); - - nm_clear_g_cancellable (&info->cancellable); - - g_signal_handlers_disconnect_by_func (info->nmc->client, connection_removed_cb, info); - g_slice_free (ConnectionCbInfo, info); - quit (); -} - static NMCResultCode do_connection_down (NmCli *nmc, int argc, char **argv) { NMActiveConnection *active; ConnectionCbInfo *info = NULL; const GPtrArray *active_cons; - GSList *queue = NULL, *iter, *next; - char **arg_arr = NULL; + gs_strfreev char **arg_arr = NULL; char **arg_ptr; int arg_num; - int idx = 0; + guint i; + gs_unref_ptrarray GPtrArray *found_active_cons = NULL; if (nmc->timeout == -1) nmc->timeout = 10; @@ -2674,108 +2670,88 @@ 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 finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } } /* Get active connections */ active_cons = nm_client_get_active_connections (nmc->client); while (arg_num > 0) { - const GPtrArray *connections; const char *selector = NULL; if (arg_num == 1 && nmc->complete) 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 - || strcmp (*arg_ptr, "apath") == 0) { - + if (NM_IN_STRSET (*arg_ptr, "id", "uuid", "path", "apath")) { selector = *arg_ptr; arg_num--; arg_ptr++; if (!arg_num) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } } - connections = nm_client_get_connections (nmc->client); - active = find_active_connection (active_cons, 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 - * NM responding for the last D-Bus call only and we would stall. */ - if (!g_slist_find (queue, active)) - queue = g_slist_prepend (queue, g_object_ref (active)); - } else { + active = nmc_find_active_connection (active_cons, + selector, + *arg_ptr, + &found_active_cons, + arg_num == 1 && nmc->complete); + if (!active) { 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; } - if (idx == 0) - next_arg (nmc->ask ? NULL : nmc, &arg_num, &arg_ptr, NULL); + next_arg (nmc->ask ? NULL : nmc, &arg_num, &arg_ptr, NULL); } - if (!queue) { + if (!found_active_cons) { g_string_printf (nmc->return_text, _("Error: no active connection provided.")); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto finish; - } else if (nmc->complete) { - g_slist_free (queue); - goto finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_NOT_FOUND); } - queue = g_slist_reverse (queue); + nm_assert (found_active_cons->len > 0); + + if (nmc->complete) + return nmc->return_value; if (nmc->timeout > 0) { nmc->should_wait++; info = g_slice_new0 (ConnectionCbInfo); info->nmc = nmc; - info->queue = queue; - info->timeout_id = g_timeout_add_seconds (nmc->timeout, connection_op_timeout_cb, info); - } - - iter = queue; - while (iter) { - GError *error = NULL; - - next = g_slist_next (iter); - active = iter->data; - - if (info) { + info->obj_list = g_ptr_array_sized_new (found_active_cons->len); + for (i = 0; i < found_active_cons->len; i++) { + active = found_active_cons->pdata[i]; + g_ptr_array_add (info->obj_list, g_object_ref (active)); g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_STATE, G_CALLBACK (down_active_connection_state_cb), info); } + info->timeout_id = g_timeout_add_seconds (nmc->timeout, connection_op_timeout_cb, info); + } + + for (i = 0; i < found_active_cons->len; i++) { + GError *error = NULL; + + active = found_active_cons->pdata[i]; - /* Now deactivate the connection */ if (!nm_client_deactivate_connection (nmc->client, active, NULL, &error)) { g_print (_("Connection '%s' deactivation failed: %s\n"), nm_active_connection_get_id (active), error->message); - g_error_free (error); + g_clear_error (&error); if (info) { g_signal_handlers_disconnect_by_func (active, down_active_connection_state_cb, info); - /* Remove the active connection from @queue */ connection_cb_info_finish (info, active); } } - - iter = next; } -finish: - g_strfreev (arg_arr); return nmc->return_value; } @@ -3339,7 +3315,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); @@ -3595,6 +3571,7 @@ set_property (NMConnection *connection, */ if (value) { unsigned long idx; + if (nmc_string_to_uint (value, TRUE, 0, G_MAXUINT32, &idx)) nmc_setting_remove_property_option (setting, property_name, NULL, idx, &local); else @@ -4265,7 +4242,7 @@ nmc_read_connection_properties (NmCli *nmc, return FALSE; if (!*argc && nmc->complete) - complete_property (setting, strv[1], value ? value : "", connection); + complete_property (setting, strv[1], value ?: "", connection); if (!set_property (connection, setting_name, strv[1], value, modifier, error)) return FALSE; @@ -4346,7 +4323,7 @@ nmc_read_connection_properties (NmCli *nmc, return FALSE; if (!*argc && nmc->complete) - complete_option (chosen, value ? value : "", connection); + complete_option (chosen, value ?: "", connection); if (!set_option (nmc, connection, chosen, value, error)) return FALSE; @@ -4457,8 +4434,8 @@ nmcli_con_add_tab_completion (const char *text, int start, int end) NMMetaSettingType s; char **match_array = NULL; rl_compentry_func_t *generator_func = NULL; - gs_free char *no = g_strdup_printf ("[%s]: ", gettext ("no")); - gs_free char *yes = g_strdup_printf ("[%s]: ", gettext ("yes")); + gs_free char *no = g_strdup_printf ("[%s]: ", _("no")); + gs_free char *yes = g_strdup_printf ("[%s]: ", _("yes")); /* Disable readline's default filename completion */ rl_attempted_completion_over = 1; @@ -4741,9 +4718,9 @@ again: static NMCResultCode do_connection_add (NmCli *nmc, int argc, char **argv) { - NMConnection *connection = NULL; + gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; - GError *error = NULL; + gs_free_error GError *error = NULL; AddConnectionInfo *info = NULL; gboolean save_bool = TRUE; gboolean seen_dash_dash = FALSE; @@ -4755,27 +4732,24 @@ do_connection_add (NmCli *nmc, int argc, char **argv) nmc->return_value = NMC_RESULT_SUCCESS; - /* Create a new connection object */ connection = nm_simple_connection_new (); - /* Build up the 'connection' setting */ s_con = (NMSettingConnection *) nm_setting_connection_new (); nm_connection_add_setting (connection, NM_SETTING (s_con)); read_properties: + g_clear_error (&error); /* Get the arguments from the command line if any */ if (argc && !nmc_read_connection_properties (nmc, connection, &argc, &argv, &error)) { if (g_strcmp0 (*argv, "--") == 0 && !seen_dash_dash) { /* This is for compatibility with older nmcli that required * options and properties to be separated with "--" */ - g_clear_error (&error); seen_dash_dash = TRUE; next_arg (nmc, &argc, &argv, NULL); goto read_properties; } else if (g_strcmp0 (*argv, "save") == 0) { /* It would be better if "save" was a separate argument and not * mixed with properties, but there's not much we can do about it now. */ - g_clear_error (&error); argc--; argv++; if (!argc) { @@ -4785,11 +4759,11 @@ read_properties: nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; goto finish; } + g_clear_error (&error); if (!nmc_string_to_bool (*argv, &save_bool, &error)) { g_string_printf (nmc->return_text, _("Error: 'save': %s."), error->message); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - g_clear_error (&error); goto finish; } next_arg (nmc, &argc, &argv, NULL); @@ -4798,7 +4772,6 @@ read_properties: g_string_assign (nmc->return_text, error->message); nmc->return_value = error->code; - g_clear_error (&error); goto finish; } @@ -4908,9 +4881,6 @@ read_properties: finish: reset_options (); - if (connection) - g_object_unref (connection); - return nmc->return_value; } @@ -4962,15 +4932,7 @@ gen_nmcli_cmds_submenu (const char *text, int state) static char * gen_cmd_nmcli (const char *text, int state) { - const char *words[] = { "status-line", "save-confirmation", "show-secrets", "prompt-color", NULL }; - return nmc_rl_gen_func_basic (text, state, words); -} - -static char * -gen_cmd_nmcli_prompt_color (const char *text, int state) -{ - const char *words[] = { "normal", "black", "red", "green", "yellow", - "blue", "magenta", "cyan", "white", NULL }; + const char *words[] = { "status-line", "save-confirmation", "show-secrets", NULL }; return nmc_rl_gen_func_basic (text, state, words); } @@ -5286,8 +5248,6 @@ get_gen_func_cmd_nmcli (const char *str) return gen_func_bool_values; if (matches (str, "show-secrets")) return gen_func_bool_values; - if (matches (str, "prompt-color")) - return gen_cmd_nmcli_prompt_color; return NULL; } @@ -5889,50 +5849,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_utils_is_separator (cmd[0])) + cmd++; + if (!cmd[0]) + return; + + l = strcspn (cmd, " \t"); + arg0 = g_strndup (cmd, l); + cmd += l; + if (cmd[0]) { + while (nm_utils_is_separator (cmd[0])) + 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 +6071,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 @@ -6259,8 +6248,8 @@ static gboolean progress_activation_editor_cb (gpointer user_data) { MonitorACInfo *info = (MonitorACInfo *) user_data; - NMDevice *device = info->device; - NMActiveConnection *ac = info->ac; + gs_unref_object NMDevice *device = info->device; + gs_unref_object NMActiveConnection *ac = info->ac; NMActiveConnectionState ac_state; NMDeviceState dev_state; @@ -6277,12 +6266,12 @@ progress_activation_editor_cb (gpointer user_data) nmc_terminal_erase_line (); g_print (_("Connection successfully activated (D-Bus active path: %s)\n"), nm_object_get_path (NM_OBJECT (ac))); - goto finish; /* we are done */ + goto finish; } else if ( ac_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED || dev_state == NM_DEVICE_STATE_FAILED) { nmc_terminal_erase_line (); g_print (_("Error: Connection activation failed.\n")); - goto finish; /* we are done */ + goto finish; } if (info->nmc->secret_agent) { @@ -6297,10 +6286,6 @@ progress_activation_editor_cb (gpointer user_data) finish: info->monitor_id = 0; - if (device) - g_object_unref (device); - if (ac) - g_object_unref (ac); return FALSE; } @@ -6405,7 +6390,7 @@ refresh_remote_connection (GWeakRef *weak, NMRemoteConnection **remote) { gboolean previous; - g_return_val_if_fail (remote != NULL, FALSE); + g_return_val_if_fail (remote, FALSE); previous = (*remote != NULL); if (*remote) @@ -6454,33 +6439,31 @@ property_edit_submenu (NmCli *nmc, const char *prop_name) { NmcEditorSubCmd cmdsub; - gboolean cmd_property_loop = TRUE; - gboolean should_quit = FALSE; - char *prop_val_user; gboolean set_result; GError *tmp_err = NULL; - char *prompt; - gboolean dirty; - GValue prop_g_value = G_VALUE_INIT; + gs_free char *prompt = NULL; gboolean temp_changes; - gboolean removed; /* Set global variable for use in TAB completion */ nmc_tab_completion.property = prop_name; - prompt = nmc_colorize (nmc->nmc_config.use_colors, nmc->editor_prompt_color, NM_META_TERM_FORMAT_NORMAL, - "nmcli %s.%s> ", + prompt = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_PROMPT, "nmcli %s.%s> ", nm_setting_get_name (curr_setting), prop_name); - while (cmd_property_loop) { - char *cmd_property_user; - char *cmd_property_arg; + for (;;) { + gs_free char *cmd_property_user = NULL; + gs_free char *cmd_property_arg = NULL; + gs_free char *prop_val_user = NULL; + nm_auto_unset_gvalue GValue prop_g_value = G_VALUE_INIT; + gboolean removed; + gboolean dirty; /* Get the remote connection again, it may have disapeared */ removed = refresh_remote_connection (rem_con_weak, rem_con); - if (removed) + if (removed) { g_print (_("The connection profile has been removed from another client. " "You may type 'save' in the main menu to restore it.\n")); + } /* Connection is dirty? (not saved or differs from the saved) */ dirty = is_connection_dirty (connection, *rem_con); @@ -6489,7 +6472,7 @@ property_edit_submenu (NmCli *nmc, editor_show_status_line (connection, dirty, temp_changes); cmd_property_user = nmc_readline ("%s", prompt); - if (!cmd_property_user || *cmd_property_user == '\0') + if (!cmd_property_user || !*cmd_property_user) continue; cmdsub = parse_editor_sub_cmd (g_strstrip (cmd_property_user), &cmd_property_arg); @@ -6525,7 +6508,6 @@ property_edit_submenu (NmCli *nmc, } set_result = nmc_setting_set_property (curr_setting, prop_name, prop_val_user, &tmp_err); - g_free (prop_val_user); if (!set_result) { g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message); g_clear_error (&tmp_err); @@ -6536,8 +6518,6 @@ property_edit_submenu (NmCli *nmc, g_signal_handlers_unblock_matched (curr_setting, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NULL); } } - if (G_IS_VALUE (&prop_g_value)) - g_value_unset (&prop_g_value); break; case NMC_EDITOR_SUB_CMD_CHANGE: @@ -6555,9 +6535,6 @@ property_edit_submenu (NmCli *nmc, nmc_property_set_gvalue (curr_setting, prop_name, &prop_g_value); g_signal_handlers_unblock_matched (curr_setting, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NULL); } - g_free (prop_val_user); - if (G_IS_VALUE (&prop_g_value)) - g_value_unset (&prop_g_value); break; case NMC_EDITOR_SUB_CMD_REMOVE: @@ -6610,8 +6587,7 @@ property_edit_submenu (NmCli *nmc, case NMC_EDITOR_SUB_CMD_BACK: /* Set global variable for use in TAB completion */ nmc_tab_completion.property = NULL; - cmd_property_loop = FALSE; - break; + return TRUE; case NMC_EDITOR_SUB_CMD_HELP: editor_sub_usage (cmd_property_arg); @@ -6619,14 +6595,10 @@ property_edit_submenu (NmCli *nmc, case NMC_EDITOR_SUB_CMD_QUIT: if (is_connection_dirty (connection, *rem_con)) { - if (confirm_quit ()) { - cmd_property_loop = FALSE; - should_quit = TRUE; /* we will quit nmcli */ - } - } else { - cmd_property_loop = FALSE; - should_quit = TRUE; /* we will quit nmcli */ - } + if (confirm_quit ()) + return FALSE; + } else + return FALSE; break; case NMC_EDITOR_SUB_CMD_UNKNOWN: @@ -6634,12 +6606,7 @@ property_edit_submenu (NmCli *nmc, g_print (_("Unknown command: '%s'\n"), cmd_property_user); break; } - g_free (cmd_property_user); - g_free (cmd_property_arg); } - g_free (prompt); - - return !should_quit; } /* @@ -6650,29 +6617,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 +6757,7 @@ confirm_connection_saving (NMConnection *local, NMConnection *remote) return confirmed; } -typedef struct { +typedef struct { guint level; char *main_prompt; NMSetting *curr_setting; @@ -6802,14 +6766,13 @@ typedef struct { } NmcEditorMenuContext; static void -menu_switch_to_level0 (NmcColorOption color_option, +menu_switch_to_level0 (const NmcConfig *nmc_config, NmcEditorMenuContext *menu_ctx, - const char *prompt, - NMMetaTermColor prompt_color) + const char *prompt) { menu_ctx->level = 0; g_free (menu_ctx->main_prompt); - menu_ctx->main_prompt = nmc_colorize (color_option, prompt_color, NM_META_TERM_FORMAT_NORMAL, "%s", prompt); + menu_ctx->main_prompt = nmc_colorize (nmc_config, NM_META_COLOR_PROMPT, "%s", prompt); menu_ctx->curr_setting = NULL; g_strfreev (menu_ctx->valid_props); menu_ctx->valid_props = NULL; @@ -6818,16 +6781,14 @@ menu_switch_to_level0 (NmcColorOption color_option, } static void -menu_switch_to_level1 (NmcColorOption color_option, +menu_switch_to_level1 (const NmcConfig *nmc_config, NmcEditorMenuContext *menu_ctx, NMSetting *setting, - const char *setting_name, - NMMetaTermColor prompt_color) + const char *setting_name) { menu_ctx->level = 1; g_free (menu_ctx->main_prompt); - menu_ctx->main_prompt = nmc_colorize (color_option, prompt_color, NM_META_TERM_FORMAT_NORMAL, - "nmcli %s> ", setting_name); + menu_ctx->main_prompt = nmc_colorize (nmc_config, NM_META_COLOR_PROMPT, "nmcli %s> ", setting_name); menu_ctx->curr_setting = setting; g_strfreev (menu_ctx->valid_props); menu_ctx->valid_props = nmc_setting_get_valid_properties (menu_ctx->curr_setting); @@ -6850,7 +6811,6 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t gs_free char *valid_settings_str = NULL; const char *s_type = NULL; AddConnectionInfo *info = NULL; - gboolean dirty; gboolean temp_changes; GError *err1 = NULL; NmcEditorMenuContext menu_ctx = { 0 }; @@ -6865,8 +6825,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t valid_settings_str = get_valid_options_string (valid_settings_main, valid_settings_slave); g_print (_("You may edit the following settings: %s\n"), valid_settings_str); - menu_ctx.main_prompt = nmc_colorize (nmc->nmc_config.use_colors, nmc->editor_prompt_color, NM_META_TERM_FORMAT_NORMAL, - BASE_PROMPT); + menu_ctx.main_prompt = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_PROMPT, BASE_PROMPT); /* Get remote connection */ con_tmp = nm_client_get_connection_by_uuid (nmc->client, @@ -6880,6 +6839,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t gs_free char *cmd_arg_s = NULL; gs_free char *cmd_arg_p = NULL; gs_free char *cmd_arg_v = NULL; + gboolean dirty; /* Connection is dirty? (not saved or differs from the saved) */ dirty = is_connection_dirty (connection, rem_con); @@ -6887,17 +6847,18 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t if (nmc->editor_status_line) editor_show_status_line (connection, dirty, temp_changes); - /* Read user input */ cmd_user = nmc_readline ("%s", menu_ctx.main_prompt); /* Get the remote connection again, it may have disapeared */ removed = refresh_remote_connection (&weak, &rem_con); - if (removed) + if (removed) { g_print (_("The connection profile has been removed from another client. " "You may type 'save' to restore it.\n")); + } - if (!cmd_user || *cmd_user == '\0') + if (!cmd_user || !*cmd_user) continue; + cmd = parse_editor_main_cmd (g_strstrip (cmd_user), &cmd_arg); split_editor_main_cmd_args (cmd_arg, &cmd_arg_s, &cmd_arg_p, &cmd_arg_v); @@ -7005,7 +6966,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t /* in top level - no setting selected yet */ const char *setting_name; NMSetting *setting; - const char *user_arg = cmd_arg_s ? cmd_arg_s : cmd_arg_p; + const char *user_arg = cmd_arg_s ?: cmd_arg_p; setting_name = ask_check_setting (user_arg, valid_settings_main, @@ -7042,7 +7003,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t nmc_tab_completion.setting = setting; /* Switch to level 1 */ - menu_switch_to_level1 (nmc->nmc_config.use_colors, &menu_ctx, setting, setting_name, nmc->editor_prompt_color); + menu_switch_to_level1 (&nmc->nmc_config, &menu_ctx, setting, setting_name); if (!cmd_arg_s) { g_print (_("You may edit the following properties: %s\n"), menu_ctx.valid_props_str); @@ -7097,7 +7058,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t /* cmd_arg_s != NULL means argument is "setting.property" */ descr_all = !cmd_arg_s && !menu_ctx.curr_setting; - user_s = descr_all ? cmd_arg_p : cmd_arg_s ? cmd_arg_s : NULL; + user_s = descr_all ? cmd_arg_p : cmd_arg_s; if (user_s) { ss = is_setting_valid (connection, valid_settings_main, @@ -7124,7 +7085,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t connection_remove_setting (connection, ss); if (ss == menu_ctx.curr_setting) { /* If we removed the setting we are in, go up */ - menu_switch_to_level0 (nmc->nmc_config.use_colors, &menu_ctx, BASE_PROMPT, nmc->editor_prompt_color); + menu_switch_to_level0 (&nmc->nmc_config, &menu_ctx, BASE_PROMPT); nmc_tab_completion.setting = NULL; /* for TAB completion */ } } else { @@ -7152,7 +7113,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t /* coverity[copy_paste_error] - suppress Coverity COPY_PASTE_ERROR defect */ if (ss == menu_ctx.curr_setting) { /* If we removed the setting we are in, go up */ - menu_switch_to_level0 (nmc->nmc_config.use_colors, &menu_ctx, BASE_PROMPT, nmc->editor_prompt_color); + menu_switch_to_level0 (&nmc->nmc_config, &menu_ctx, BASE_PROMPT); nmc_tab_completion.setting = NULL; /* for TAB completion */ } } else @@ -7190,7 +7151,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t /* cmd_arg_s != NULL means argument is "setting.property" */ descr_all = !cmd_arg_s && !menu_ctx.curr_setting; - user_s = descr_all ? cmd_arg_p : cmd_arg_s ? cmd_arg_s : NULL; + user_s = descr_all ? cmd_arg_p : cmd_arg_s; if (user_s) { ss = is_setting_valid (connection, valid_settings_main, @@ -7247,7 +7208,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t case NMC_EDITOR_MAIN_CMD_PRINT: /* Print current connection settings/properties */ if (cmd_arg) { - if (strcmp (cmd_arg, "all") == 0) + if (nm_streq (cmd_arg, "all")) editor_show_connection (connection, nmc); else { NMSetting *ss = NULL; @@ -7256,7 +7217,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t /* cmd_arg_s != NULL means argument is "setting.property" */ whole_setting = !cmd_arg_s && !menu_ctx.curr_setting; - user_s = whole_setting ? cmd_arg_p : cmd_arg_s ? cmd_arg_s : NULL; + user_s = whole_setting ? cmd_arg_p : cmd_arg_s; if (user_s) { const char *s_name; @@ -7508,7 +7469,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t case NMC_EDITOR_MAIN_CMD_BACK: /* Go back (up) an the menu */ if (menu_ctx.level == 1) { - menu_switch_to_level0 (nmc->nmc_config.use_colors, &menu_ctx, BASE_PROMPT, nmc->editor_prompt_color); + menu_switch_to_level0 (&nmc->nmc_config, &menu_ctx, BASE_PROMPT); nmc_tab_completion.setting = NULL; /* for TAB completion */ } break; @@ -7544,37 +7505,18 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t } else nmc->nmc_config_mutable.show_secrets = bb; } else if (cmd_arg_p && matches (cmd_arg_p, "prompt-color")) { - GError *tmp_err = NULL; - NMMetaTermColor color; - color = nmc_term_color_parse_string (cmd_arg_v ? g_strstrip (cmd_arg_v) : " ", &tmp_err); - if (tmp_err) { - g_print (_("Error: bad color: %s\n"), tmp_err->message); - g_clear_error (&tmp_err); - } else { - nmc->editor_prompt_color = color; - nm_clear_g_free (&menu_ctx.main_prompt); - if (menu_ctx.level == 0) { - menu_ctx.main_prompt = nmc_colorize (nmc->nmc_config.use_colors, nmc->editor_prompt_color, NM_META_TERM_FORMAT_NORMAL, - BASE_PROMPT); - } else { - menu_ctx.main_prompt = nmc_colorize (nmc->nmc_config.use_colors, nmc->editor_prompt_color, NM_META_TERM_FORMAT_NORMAL, - "nmcli %s> ", - nm_setting_get_name (menu_ctx.curr_setting)); - } - } + g_debug ("Ignoring erroneous --prompt-color argument. Use terminal-colors.d(5) to set the prompt color.\n"); } else if (!cmd_arg_p) { g_print (_("Current nmcli configuration:\n")); g_print ("status-line: %s\n" "save-confirmation: %s\n" - "show-secrets: %s\n" - "prompt-color: %d\n", + "show-secrets: %s\n", nmc->editor_status_line ? "yes" : "no", nmc->editor_save_confirmation ? "yes" : "no", - nmc->nmc_config.show_secrets ? "yes" : "no", - nmc->editor_prompt_color); + nmc->nmc_config.show_secrets ? "yes" : "no"); } else g_print (_("Invalid configuration option '%s'; allowed [%s]\n"), - cmd_arg_v ? cmd_arg_v : "", "status-line, save-confirmation, show-secrets, prompt-color"); + cmd_arg_v ?: "", "status-line, save-confirmation, show-secrets"); break; @@ -7645,7 +7587,7 @@ editor_init_new_connection (NmCli *nmc, NMConnection *connection, const char *sl g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_CONNECTION_MASTER, dev_ifname ? dev_ifname : "eth0", + NM_SETTING_CONNECTION_MASTER, dev_ifname ?: "eth0", NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type, NULL); } else { @@ -7666,11 +7608,10 @@ editor_init_new_connection (NmCli *nmc, NMConnection *connection, const char *sl const char *dev_ifname = get_ethernet_device_name (nmc); g_object_set (NM_SETTING_VLAN (base_setting), - NM_SETTING_VLAN_PARENT, dev_ifname ? dev_ifname : "eth0", + NM_SETTING_VLAN_PARENT, dev_ifname ?: "eth0", NULL); } - setting = nm_meta_setting_info_editor_new_setting (&nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_IP4_CONFIG], NM_META_ACCESSOR_SETTING_INIT_TYPE_CLI); nm_connection_add_setting (connection, setting); @@ -7731,28 +7672,24 @@ static NMCResultCode do_connection_edit (NmCli *nmc, int argc, char **argv) { const GPtrArray *connections; - NMConnection *connection = NULL; + gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; const char *connection_type; - char *uuid; - char *default_name = NULL; const char *type = NULL; - char *type_ask = NULL; const char *con_name = NULL; const char *con = NULL; const char *con_id = NULL; const char *con_uuid = NULL; const char *con_path = NULL; const char *selector = NULL; - char *tmp_str; - GError *error = NULL; + gs_free_error GError *error = NULL; GError *err1 = NULL; - nmc_arg_t exp_args[] = { {"type", TRUE, &type, FALSE}, - {"con-name", TRUE, &con_name, FALSE}, - {"id", TRUE, &con_id, FALSE}, - {"uuid", TRUE, &con_uuid, FALSE}, - {"path", TRUE, &con_path, FALSE}, - {NULL} }; + nmc_arg_t exp_args[] = { { "type", TRUE, &type, FALSE }, + { "con-name", TRUE, &con_name, FALSE }, + { "id", TRUE, &con_id, FALSE }, + { "uuid", TRUE, &con_uuid, FALSE }, + { "path", TRUE, &con_path, FALSE }, + { NULL } }; next_arg (nmc, &argc, &argv, NULL); if (argc == 1 && nmc->complete) @@ -7765,9 +7702,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) else { if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, &error)) { g_string_assign (nmc->return_text, error->message); - nmc->return_value = error->code; - g_clear_error (&error); - goto error; + NMC_RETURN (nmc, error->code); } } @@ -7794,8 +7729,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) } else { g_string_printf (nmc->return_text, _("Error: only one of 'id', uuid, or 'path' can be provided.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } } @@ -7805,12 +7739,11 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) found_con = nmc_find_connection (connections, selector, con, NULL, nmc->complete); if (nmc->complete) - goto error; + return nmc->return_value; if (!found_con) { g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), con); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; + NMC_RETURN (nmc, NMC_RESULT_ERROR_NOT_FOUND); } /* Duplicate the connection and use that so that we need not @@ -7822,7 +7755,6 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) update_secrets_in_connection (NM_REMOTE_CONNECTION (found_con), connection); s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); connection_type = nm_setting_connection_get_connection_type (s_con); if (type) @@ -7838,18 +7770,23 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) editor_init_existing_connection (connection); } else { const char *slave_type = NULL; + gs_free char *uuid = NULL; + gs_free char *default_name = NULL; + gs_free char *tmp_str = NULL; /* New connection */ if (nmc->complete) { if (type && argc == 0) nmc_complete_connection_type (type); - goto error; + return nmc->return_value; } connection_type = check_valid_name_toplevel (type, &slave_type, &err1); tmp_str = get_valid_options_string_toplevel (); while (!connection_type) { + gs_free char *type_ask = NULL; + if (!type) g_print (_("Valid connection types: %s\n"), tmp_str); else @@ -7859,14 +7796,11 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) type_ask = nmc_readline (EDITOR_PROMPT_CON_TYPE); type = type_ask = type_ask ? g_strstrip (type_ask) : NULL; connection_type = check_valid_name_toplevel (type_ask, &slave_type, &err1); - g_free (type_ask); } - g_free (tmp_str); + nm_clear_g_free (&tmp_str); - /* Create a new connection object */ connection = nm_simple_connection_new (); - /* Build up the 'connection' setting */ s_con = (NMSettingConnection *) nm_setting_connection_new (); uuid = nm_utils_uuid_generate (); if (con_name) @@ -7881,8 +7815,6 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) NM_SETTING_CONNECTION_UUID, uuid, NM_SETTING_CONNECTION_TYPE, connection_type, NULL); - g_free (uuid); - g_free (default_name); nm_connection_add_setting (connection, NM_SETTING (s_con)); /* Initialize the new connection so that it is valid from the start */ @@ -7905,7 +7837,6 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) g_print (_("Type 'describe [<setting>.<prop>]' for detailed property description.")); g_print ("\n\n"); - /* Set global variables for use in TAB completion */ nmc_tab_completion.nmc = nmc; nmc_tab_completion.con_type = g_strdup (connection_type); nmc_tab_completion.connection = connection; @@ -7913,15 +7844,9 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) /* Run menu loop */ editor_menu_main (nmc, connection, connection_type); - if (connection) - g_object_unref (connection); - g_free (nmc_tab_completion.con_type); - - return nmc->return_value; - -error: - g_assert (!connection); - g_free (type_ask); + nmc_tab_completion.nmc = NULL; + nm_clear_g_free (&nmc_tab_completion.con_type); + nmc_tab_completion.connection = NULL; return nmc->return_value; } @@ -7931,8 +7856,8 @@ modify_connection_cb (GObject *connection, GAsyncResult *result, gpointer user_data) { - NmCli *nmc = (NmCli *) user_data; - GError *error = NULL; + NmCli *nmc = user_data; + gs_free_error GError *error = NULL; if (!nm_remote_connection_commit_changes_finish (NM_REMOTE_CONNECTION (connection), result, &error)) { @@ -7940,13 +7865,13 @@ modify_connection_cb (GObject *connection, _("Error: Failed to modify connection '%s': %s"), nm_connection_get_id (NM_CONNECTION (connection)), error->message); - g_error_free (error); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; } else { - if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) + if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) { g_print (_("Connection '%s' (%s) successfully modified.\n"), nm_connection_get_id (NM_CONNECTION (connection)), nm_connection_get_uuid (NM_CONNECTION (connection))); + } } quit (); } @@ -7958,20 +7883,18 @@ do_connection_modify (NmCli *nmc, { NMConnection *connection = NULL; NMRemoteConnection *rc = NULL; - GError *error = NULL; + gs_free_error GError *error = NULL; gboolean temporary = FALSE; - /* Check --temporary */ if (next_arg (nmc, &argc, &argv, "--temporary", NULL) > 0) { temporary = TRUE; next_arg (nmc, &argc, &argv, NULL); } - connection = get_connection (nmc, &argc, &argv, NULL, &error); + connection = get_connection (nmc, &argc, &argv, NULL, NULL, NULL, &error); if (!connection) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); - nmc->return_value = error->code; - goto finish; + NMC_RETURN (nmc, error->code); } rc = nm_client_get_connection_by_uuid (nmc->client, @@ -7979,24 +7902,20 @@ do_connection_modify (NmCli *nmc, if (!rc) { 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; + NMC_RETURN (nmc, NMC_RESULT_ERROR_NOT_FOUND); } if (!nmc_read_connection_properties (nmc, NM_CONNECTION (rc), &argc, &argv, &error)) { g_string_assign (nmc->return_text, error->message); - nmc->return_value = error->code; - g_clear_error (&error); - goto finish; + NMC_RETURN (nmc, error->code); } if (nmc->complete) - goto finish; + return nmc->return_value; update_connection (!temporary, rc, modify_connection_cb, nmc); nmc->should_wait++; -finish: return nmc->return_value; } @@ -8044,11 +7963,11 @@ static NMCResultCode do_connection_clone (NmCli *nmc, int argc, char **argv) { NMConnection *connection = NULL; - NMConnection *new_connection = NULL; + gs_unref_object NMConnection *new_connection = NULL; NMSettingConnection *s_con; CloneConnectionInfo *info; const char *new_name; - char *new_name_ask = NULL; + gs_free char *new_name_ask = NULL; char *uuid; gboolean temporary = FALSE; char **arg_arr = NULL; @@ -8078,15 +7997,14 @@ do_connection_clone (NmCli *nmc, int argc, char **argv) argc_ptr = &arg_num; } - connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, &error); + connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, NULL, NULL, &error); if (!connection) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); - nmc->return_value = error->code; - goto finish; + NMC_RETURN (nmc, error->code); } if (nmc->complete) - goto finish; + return nmc->return_value; if (argv[0]) new_name = *argv; @@ -8094,14 +8012,12 @@ do_connection_clone (NmCli *nmc, int argc, char **argv) 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; + NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } if (next_arg (nmc->ask ? NULL : nmc, argc_ptr, argv_ptr, NULL) == 0) { g_string_printf (nmc->return_text, _("Error: unknown extra argument: '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } /* Copy the connection */ @@ -8133,11 +8049,6 @@ do_connection_clone (NmCli *nmc, int argc, char **argv) info); nmc->should_wait++; -finish: - if (new_connection) - g_object_unref (new_connection); - g_free (new_name_ask); - return nmc->return_value; } @@ -8167,12 +8078,12 @@ do_connection_delete (NmCli *nmc, int argc, char **argv) { NMConnection *connection; ConnectionCbInfo *info = NULL; - GSList *queue = NULL, *iter; - char **arg_arr = NULL, *old_arg; + gs_strfreev char **arg_arr = NULL; char **arg_ptr; + guint i; int arg_num; - GString *invalid_cons = NULL; - int pos = 0; + nm_auto_free_gstring GString *invalid_cons = NULL; + gs_unref_ptrarray GPtrArray *found_cons = NULL; GError *error = NULL; if (nmc->timeout == -1) @@ -8202,15 +8113,10 @@ do_connection_delete (NmCli *nmc, int argc, char **argv) } while (arg_num > 0) { - old_arg = *arg_ptr; - 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 - * NM responding for the last D-Bus call only and we would stall. */ - if (!g_slist_find (queue, connection)) - queue = g_slist_prepend (queue, g_object_ref (connection)); - } else { + const char *cur_selector, *cur_value; + + connection = get_connection (nmc, &arg_num, &arg_ptr, &cur_selector, &cur_value, &found_cons, &error); + if (!connection) { if (!nmc->complete) g_printerr (_("Error: %s.\n"), error->message); g_string_printf (nmc->return_text, _("Error: not all connections found.")); @@ -8222,23 +8128,31 @@ do_connection_delete (NmCli *nmc, int argc, char **argv) if (!invalid_cons) invalid_cons = g_string_new (NULL); - g_string_append_printf (invalid_cons, "'%s', ", old_arg); + if (cur_selector) + g_string_append_printf (invalid_cons, "%s '%s', ", cur_selector, cur_value); + else + g_string_append_printf (invalid_cons, "'%s', ", cur_value); } } - if (!queue) { - 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); + if (!found_cons) { + if (!invalid_cons) { + g_string_printf (nmc->return_text, _("Error: No connection specified.")); + nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; + } goto finish; } - queue = g_slist_reverse (queue); + + if (nmc->complete) + goto finish; info = g_slice_new0 (ConnectionCbInfo); info->nmc = nmc; - info->queue = queue; + info->obj_list = g_ptr_array_sized_new (found_cons->len); + for (i = 0; i < found_cons->len; i++) { + connection = found_cons->pdata[i]; + g_ptr_array_add (info->obj_list, g_object_ref (connection)); + } info->timeout_id = g_timeout_add_seconds (nmc->timeout, connection_op_timeout_cb, info); info->cancellable = g_cancellable_new (); @@ -8248,10 +8162,10 @@ do_connection_delete (NmCli *nmc, int argc, char **argv) g_signal_connect (nmc->client, NM_CLIENT_CONNECTION_REMOVED, G_CALLBACK (connection_removed_cb), info); - /* Now delete the connections */ - for (iter = queue; iter; iter = g_slist_next (iter)) - nm_remote_connection_delete_async (NM_REMOTE_CONNECTION (iter->data), + for (i = 0; i < found_cons->len; i++) { + nm_remote_connection_delete_async (NM_REMOTE_CONNECTION (found_cons->pdata[i]), info->cancellable, delete_cb, info); + } finish: if (invalid_cons) { @@ -8259,9 +8173,7 @@ finish: g_string_printf (nmc->return_text, _("Error: cannot delete unknown connection(s): %s."), invalid_cons->str); nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - g_string_free (invalid_cons, TRUE); } - g_strfreev (arg_arr); return nmc->return_value; } @@ -8311,31 +8223,21 @@ static NMCResultCode do_connection_monitor (NmCli *nmc, int argc, char **argv) { GError *error = NULL; + guint i; + gs_unref_ptrarray GPtrArray *found_cons = NULL; + const GPtrArray *connections = NULL; next_arg (nmc, &argc, &argv, NULL); if (argc == 0) { /* No connections specified. Monitor all. */ - const GPtrArray *connections; - int i; /* nmc_do_cmd() should not call this with argc=0. */ g_assert (!nmc->complete); connections = nm_client_get_connections (nmc->client); - for (i = 0; i < connections->len; i++) - connection_watch (nmc, g_ptr_array_index (connections, i)); - - /* We'll watch the connection additions too, never exit. */ - nmc->should_wait++; - g_signal_connect (nmc->client, NM_CLIENT_CONNECTION_ADDED, G_CALLBACK (connection_added), nmc); } else { - /* Look up the specified connections and watch them. */ - NMConnection *connection; - int pos = 0; - - do { - connection = get_connection (nmc, &argc, &argv, &pos, &error); - if (!connection) { + while (argc > 0) { + if (!get_connection (nmc, &argc, &argv, NULL, NULL, &found_cons, &error)) { if (!nmc->complete) g_printerr (_("Error: %s.\n"), error->message); g_string_printf (nmc->return_text, _("Error: not all connections found.")); @@ -8345,8 +8247,17 @@ do_connection_monitor (NmCli *nmc, int argc, char **argv) if (nmc->complete) continue; - connection_watch (nmc, connection); - } while (argc > 0); + connections = found_cons; + } + } + + for (i = 0; i < connections->len; i++) + connection_watch (nmc, connections->pdata[i]); + + if (argc == 0) { + /* We'll watch the connection additions too, never exit. */ + nmc->should_wait++; + g_signal_connect (nmc->client, NM_CLIENT_CONNECTION_ADDED, G_CALLBACK (connection_added), nmc); } if (nmc->complete) @@ -8419,11 +8330,12 @@ do_connection_load (NmCli *nmc, int argc, char **argv) static NMCResultCode do_connection_import (NmCli *nmc, int argc, char **argv) { - GError *error = NULL; + gs_free_error GError *error = NULL; const char *type = NULL, *filename = NULL; - char *type_ask = NULL, *filename_ask = NULL; + gs_free char *type_ask = NULL; + gs_free char *filename_ask = NULL; AddConnectionInfo *info; - NMConnection *connection = NULL; + gs_unref_object NMConnection *connection = NULL; NMVpnEditorPlugin *plugin; gs_free char *service_type = NULL; gboolean temporary = FALSE; @@ -8434,7 +8346,6 @@ do_connection_import (NmCli *nmc, int argc, char **argv) next_arg (nmc, &argc, &argv, NULL); } - if (argc == 0) { /* nmc_do_cmd() should not call this with argc=0. */ g_assert (!nmc->complete); @@ -8446,8 +8357,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv) filename = filename_ask = filename_ask ? g_strstrip (filename_ask) : NULL; } else { g_string_printf (nmc->return_text, _("Error: No arguments provided.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } } @@ -8460,8 +8370,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } if (argc == 1 && nmc->complete) @@ -8477,8 +8386,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } if (argc == 1 && nmc->complete) nmc->return_value = NMC_RESULT_COMPLETE_FILE; @@ -8488,32 +8396,28 @@ do_connection_import (NmCli *nmc, int argc, char **argv) g_printerr (_("Warning: 'file' already specified, ignoring extra one.\n")); } else { g_string_printf (nmc->return_text, _("Unknown parameter: %s"), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } next_arg (nmc, &argc, &argv, NULL); } if (nmc->complete) - goto finish; + return nmc->return_value; if (!type) { g_string_printf (nmc->return_text, _("Error: 'type' argument is required.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } if (!filename) { g_string_printf (nmc->return_text, _("Error: 'file' argument is required.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } service_type = nm_vpn_plugin_info_list_find_service_type (nm_vpn_get_plugin_infos (), type); if (!service_type) { g_string_printf (nmc->return_text, _("Error: failed to find VPN plugin for %s."), type); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN); } /* Import VPN configuration */ @@ -8521,16 +8425,14 @@ do_connection_import (NmCli *nmc, int argc, char **argv) if (!plugin) { g_string_printf (nmc->return_text, _("Error: failed to load VPN plugin: %s."), error->message); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN); } connection = nm_vpn_editor_plugin_import (plugin, filename, &error); if (!connection) { g_string_printf (nmc->return_text, _("Error: failed to import '%s': %s."), filename, error->message); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto finish; + NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN); } info = g_malloc0 (sizeof (AddConnectionInfo)); @@ -8545,12 +8447,6 @@ do_connection_import (NmCli *nmc, int argc, char **argv) info); nmc->should_wait++; -finish: - if (connection) - g_object_unref (connection); - g_clear_error (&error); - g_free (type_ask); - g_free (filename_ask); return nmc->return_value; } @@ -8559,12 +8455,11 @@ do_connection_export (NmCli *nmc, int argc, char **argv) { NMConnection *connection = NULL; const char *out_name = NULL; - char *name_ask = NULL; - char *out_name_ask = NULL; + gs_free char *out_name_ask = NULL; const char *path = NULL; const char *type = NULL; NMVpnEditorPlugin *plugin; - GError *error = NULL; + gs_free_error GError *error = NULL; char tmpfile[] = "/tmp/nmcli-export-temp-XXXXXX"; char **arg_arr = NULL; int arg_num; @@ -8588,7 +8483,7 @@ do_connection_export (NmCli *nmc, int argc, char **argv) argc_ptr = &arg_num; } - connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, &error); + connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, NULL, NULL, &error); if (!connection) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); nmc->return_value = error->code; @@ -8629,14 +8524,14 @@ do_connection_export (NmCli *nmc, int argc, char **argv) if (out_name) path = out_name; else { - int fd; + nm_auto_close int fd = -1; + fd = g_mkstemp (tmpfile); if (fd == -1) { g_string_printf (nmc->return_text, _("Error: failed to create temporary file %s."), tmpfile); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; goto finish; } - nm_close (fd); path = tmpfile; } @@ -8649,8 +8544,9 @@ do_connection_export (NmCli *nmc, int argc, char **argv) /* No output file -> copy data to stdout */ if (!out_name) { - char *contents = NULL; + gs_free char *contents = NULL; gsize len = 0; + if (!g_file_get_contents (path, &contents, &len, &error)) { g_string_printf (nmc->return_text, _("Error: failed to read temporary file '%s': %s."), path, error->message); @@ -8658,15 +8554,11 @@ do_connection_export (NmCli *nmc, int argc, char **argv) goto finish; } g_print ("%s", contents); - g_free (contents); } finish: if (!out_name && path) unlink (path); - g_clear_error (&error); - g_free (name_ask); - g_free (out_name_ask); return nmc->return_value; } diff --git a/clients/cli/connections.h b/clients/cli/connections.h index 01e78b02..591e9cda 100644 --- a/clients/cli/connections.h +++ b/clients/cli/connections.h @@ -14,7 +14,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2010 - 2014 Red Hat, Inc. + * (C) Copyright 2010 - 2018 Red Hat, Inc. */ #ifndef NMC_CONNECTIONS_H @@ -33,7 +33,7 @@ nmc_read_connection_properties (NmCli *nmc, char ***argv, GError **error); -void nmc_active_connection_state_to_color (NMActiveConnectionState state, NMMetaTermColor *color); +NMMetaColor nmc_active_connection_state_to_color (NMActiveConnectionState state); extern const NmcMetaGenericInfo *const nmc_fields_con_show[]; extern const NmcMetaGenericInfo *const nmc_fields_con_active_details_general[]; diff --git a/clients/cli/devices.c b/clients/cli/devices.c index da969fbe..b99e606a 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -14,7 +14,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2010 - 2014 Red Hat, Inc. + * Copyright 2010 - 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -51,7 +51,6 @@ const NmcMetaGenericInfo *const nmc_fields_dev_status[] = { }; #define NMC_FIELDS_DEV_STATUS_COMMON "DEVICE,TYPE,STATE,CONNECTION" - const NmcMetaGenericInfo *const nmc_fields_dev_show_general[] = { NMC_META_GENERIC ("NAME"), /* 0 */ NMC_META_GENERIC ("DEVICE"), /* 1 */ @@ -210,9 +209,9 @@ const NmcMetaGenericInfo *const nmc_fields_dev_show_sections[] = { NMC_META_GENERIC_WITH_NESTED ("WIMAX-PROPERTIES", nmc_fields_dev_show_wimax_prop + 1), /* 5 */ NMC_META_GENERIC_WITH_NESTED ("NSP", nmc_fields_dev_wimax_list + 1), /* 6 */ NMC_META_GENERIC_WITH_NESTED ("IP4", metagen_ip4_config), /* 7 */ - NMC_META_GENERIC_WITH_NESTED ("DHCP4", nmc_fields_dhcp4_config + 1), /* 8 */ + NMC_META_GENERIC_WITH_NESTED ("DHCP4", nmc_fields_dhcp_config + 1), /* 8 */ NMC_META_GENERIC_WITH_NESTED ("IP6", nmc_fields_ip6_config + 1), /* 9 */ - NMC_META_GENERIC_WITH_NESTED ("DHCP6", nmc_fields_dhcp6_config + 1), /* 10 */ + NMC_META_GENERIC_WITH_NESTED ("DHCP6", nmc_fields_dhcp_config + 1), /* 10 */ NMC_META_GENERIC_WITH_NESTED ("BOND", nmc_fields_dev_show_master_prop + 1), /* 11 */ NMC_META_GENERIC_WITH_NESTED ("TEAM", nmc_fields_dev_show_team_prop + 1), /* 12 */ NMC_META_GENERIC_WITH_NESTED ("BRIDGE", nmc_fields_dev_show_master_prop + 1), /* 13 */ @@ -451,11 +450,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); } @@ -711,22 +707,19 @@ sort_access_points (const GPtrArray *aps) return sorted; } -static void -wifi_signal_to_color (guint8 strength, NMMetaTermColor *color, NMMetaTermFormat *color_fmt) +static NMMetaColor +wifi_signal_to_color (guint8 strength) { - *color = NM_META_TERM_COLOR_NORMAL; - *color_fmt = NM_META_TERM_FORMAT_NORMAL; - if (strength > 80) - *color = NM_META_TERM_COLOR_GREEN; + return NM_META_COLOR_WIFI_SIGNAL_EXCELLENT; else if (strength > 55) - *color = NM_META_TERM_COLOR_YELLOW; + return NM_META_COLOR_WIFI_SIGNAL_GOOD; else if (strength > 30) - *color = NM_META_TERM_COLOR_MAGENTA; + return NM_META_COLOR_WIFI_SIGNAL_FAIR; else if (strength > 5) - *color = NM_META_TERM_COLOR_CYAN; + return NM_META_COLOR_WIFI_SIGNAL_POOR; else - *color_fmt = NM_META_TERM_FORMAT_DIM; + return NM_META_COLOR_WIFI_SIGNAL_UNKNOWN; } static char * @@ -799,8 +792,7 @@ fill_output_access_point (gpointer data, gpointer user_data) GString *security_str; char *ap_name; const char *sig_bars; - NMMetaTermColor color; - NMMetaTermFormat color_fmt; + NMMetaColor color; if (info->active_bssid) { const char *current_bssid = nm_access_point_get_bssid (ap); @@ -834,7 +826,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); @@ -886,11 +878,10 @@ fill_output_access_point (gpointer data, gpointer user_data) set_val_strc (arr, 16, nm_object_get_path (NM_OBJECT (ap))); /* Set colors */ - wifi_signal_to_color (strength, &color, &color_fmt); + color = wifi_signal_to_color (strength); set_val_color_all (arr, color); - set_val_color_fmt_all (arr, color_fmt); if (active) - arr[15].color = NM_META_TERM_COLOR_GREEN; + arr[15].color = NM_META_COLOR_CONNECTION_ACTIVATED; g_ptr_array_add (info->output_data, arr); @@ -1164,7 +1155,7 @@ show_device_info (NMDevice *device, NmCli *nmc) set_val_strc (arr, 6, nm_device_get_driver (device) ? nm_device_get_driver (device) : _("(unknown)")); set_val_strc (arr, 7, nm_device_get_driver_version (device)); set_val_strc (arr, 8, nm_device_get_firmware_version (device)); - set_val_strc (arr, 9, hwaddr ? hwaddr : _("(unknown)")); + set_val_strc (arr, 9, hwaddr ?: _("(unknown)")); set_val_str (arr, 10, mtu_str); set_val_str (arr, 11, state_str); set_val_str (arr, 12, reason_str); @@ -1272,7 +1263,7 @@ show_device_info (NMDevice *device, NmCli *nmc) } tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_dev_wifi_list; - out_indices = parse_output_fields (section_fld ? section_fld : NMC_FIELDS_DEV_WIFI_LIST_FOR_DEV_LIST, + out_indices = parse_output_fields (section_fld ?: NMC_FIELDS_DEV_WIFI_LIST_FOR_DEV_LIST, tmpl, FALSE, NULL, NULL); arr = nmc_dup_fields_array (tmpl, NMC_OF_FLAG_FIELD_NAMES); g_ptr_array_add (out.output_data, arr); @@ -1332,7 +1323,7 @@ show_device_info (NMDevice *device, NmCli *nmc) /* DHCP4 */ if (dhcp4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[8]->name)) - was_output = print_dhcp4_config (dhcp4, &nmc->nmc_config, nmc_fields_dev_show_sections[8]->name, section_fld); + was_output = print_dhcp_config (dhcp4, &nmc->nmc_config, nmc_fields_dev_show_sections[8]->name, section_fld); /* IP6 */ if (cfg6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[9]->name)) @@ -1340,7 +1331,7 @@ show_device_info (NMDevice *device, NmCli *nmc) /* DHCP6 */ if (dhcp6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[10]->name)) - was_output = print_dhcp6_config (dhcp6, &nmc->nmc_config, nmc_fields_dev_show_sections[10]->name, section_fld); + was_output = print_dhcp_config (dhcp6, &nmc->nmc_config, nmc_fields_dev_show_sections[10]->name, section_fld); /* Bond specific information */ if (NM_IS_DEVICE_BOND (device)) { @@ -1467,20 +1458,19 @@ show_device_info (NMDevice *device, NmCli *nmc) return TRUE; } -void -nmc_device_state_to_color (NMDeviceState state, NMMetaTermColor *color, NMMetaTermFormat *color_fmt) +NMMetaColor +nmc_device_state_to_color (NMDeviceState state) { - *color = NM_META_TERM_COLOR_NORMAL; - *color_fmt = NM_META_TERM_FORMAT_NORMAL; - if (state <= NM_DEVICE_STATE_UNAVAILABLE) - *color_fmt= NM_META_TERM_FORMAT_DIM; + return NM_META_COLOR_DEVICE_UNAVAILABLE; else if (state == NM_DEVICE_STATE_DISCONNECTED) - *color = NM_META_TERM_COLOR_RED; + return NM_META_COLOR_DEVICE_DISCONNECTED; else if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_SECONDARIES) - *color = NM_META_TERM_COLOR_YELLOW; + return NM_META_COLOR_DEVICE_ACTIVATING; else if (state == NM_DEVICE_STATE_ACTIVATED) - *color = NM_META_TERM_COLOR_GREEN; + return NM_META_COLOR_DEVICE_ACTIVATED; + + g_return_val_if_reached (NM_META_COLOR_DEVICE_UNKNOWN); } static void @@ -1488,8 +1478,7 @@ fill_output_device_status (NMDevice *device, GPtrArray *output_data) { NMActiveConnection *ac; NMDeviceState state; - NMMetaTermColor color; - NMMetaTermFormat color_fmt; + NMMetaColor color; NmcOutputField *arr = nmc_dup_fields_array ((const NMMetaAbstractInfo *const*) nmc_fields_dev_status, 0); @@ -1497,9 +1486,8 @@ fill_output_device_status (NMDevice *device, GPtrArray *output_data) ac = nm_device_get_active_connection (device); /* Show devices in color */ - nmc_device_state_to_color (state, &color, &color_fmt); + color = nmc_device_state_to_color (state); set_val_color_all (arr, color); - set_val_color_fmt_all (arr, color_fmt); set_val_strc (arr, 0, nm_device_get_iface (device)); set_val_strc (arr, 1, nm_device_get_type_description (device)); @@ -2410,12 +2398,11 @@ static void device_state (NMDevice *device, GParamSpec *pspec, NmCli *nmc) { NMDeviceState state = nm_device_get_state (device); - NMMetaTermColor color; - NMMetaTermFormat color_fmt; + NMMetaColor color; char *str; - nmc_device_state_to_color (state, &color, &color_fmt); - str = nmc_colorize (nmc->nmc_config.use_colors, color, color_fmt, "%s: %s\n", + color = nmc_device_state_to_color (state); + str = nmc_colorize (&nmc->nmc_config, color, "%s: %s\n", nm_device_get_iface (device), nmc_device_state_to_string (state)); @@ -2910,7 +2897,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) if (nmc->ask) { ssid_ask = nmc_readline (_("SSID or BSSID: ")); - param_user = ssid_ask ? ssid_ask : ""; + param_user = ssid_ask ?: ""; bssid1_arr = nm_utils_hwaddr_atoba (param_user, ETH_ALEN); } if (!ssid_ask) { @@ -3661,7 +3648,6 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv) goto finish; } - if (ssids->len) { g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aay")); diff --git a/clients/cli/devices.h b/clients/cli/devices.h index 2c261bc7..c78680da 100644 --- a/clients/cli/devices.h +++ b/clients/cli/devices.h @@ -14,7 +14,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2010 Red Hat, Inc. + * (C) Copyright 2010 - 2018 Red Hat, Inc. */ #ifndef NMC_DEVICES_H @@ -32,7 +32,7 @@ void monitor_devices (NmCli *nmc); NMDevice ** nmc_get_devices_sorted (NMClient *client); -void nmc_device_state_to_color (NMDeviceState state, NMMetaTermColor *color, NMMetaTermFormat *color_fmt); +NMMetaColor nmc_device_state_to_color (NMDeviceState state); extern const NmcMetaGenericInfo *const nmc_fields_dev_status[]; extern const NmcMetaGenericInfo *const nmc_fields_dev_show_general[]; diff --git a/clients/cli/general.c b/clients/cli/general.c index 7ac6b22c..841df8bd 100644 --- a/clients/cli/general.c +++ b/clients/cli/general.c @@ -14,7 +14,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2010 - 2017 Red Hat, Inc. + * Copyright 2010 - 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -55,23 +55,26 @@ nm_state_to_string (NMState state) return _(nm_state_to_string_no_l10n (state)); } -static NMMetaTermColor +static NMMetaColor state_to_color (NMState state) { switch (state) { case NM_STATE_CONNECTING: - return NM_META_TERM_COLOR_YELLOW; + return NM_META_COLOR_STATE_CONNECTING; case NM_STATE_CONNECTED_LOCAL: + return NM_META_COLOR_STATE_CONNECTED_LOCAL; case NM_STATE_CONNECTED_SITE: + return NM_META_COLOR_STATE_CONNECTED_SITE; case NM_STATE_CONNECTED_GLOBAL: - return NM_META_TERM_COLOR_GREEN; + return NM_META_COLOR_STATE_CONNECTED_GLOBAL; case NM_STATE_DISCONNECTING: - return NM_META_TERM_COLOR_YELLOW; + return NM_META_COLOR_STATE_DISCONNECTING; case NM_STATE_ASLEEP: + return NM_META_COLOR_STATE_ASLEEP; case NM_STATE_DISCONNECTED: - return NM_META_TERM_COLOR_RED; + return NM_META_COLOR_STATE_DISCONNECTED; default: - return NM_META_TERM_COLOR_NORMAL; + return NM_META_COLOR_STATE_UNKNOWN; } } @@ -90,19 +93,20 @@ nm_connectivity_to_string (NMConnectivityState connectivity) return _(nm_connectivity_to_string_no_l10n (connectivity)); } -static NMMetaTermColor +static NMMetaColor connectivity_to_color (NMConnectivityState connectivity) { switch (connectivity) { case NM_CONNECTIVITY_NONE: - return NM_META_TERM_COLOR_RED; + return NM_META_COLOR_CONNECTIVITY_NONE; case NM_CONNECTIVITY_PORTAL: + return NM_META_COLOR_CONNECTIVITY_PORTAL; case NM_CONNECTIVITY_LIMITED: - return NM_META_TERM_COLOR_YELLOW; + return NM_META_COLOR_CONNECTIVITY_LIMITED; case NM_CONNECTIVITY_FULL: - return NM_META_TERM_COLOR_GREEN; + return NM_META_COLOR_CONNECTIVITY_FULL; default: - return NM_META_TERM_COLOR_NORMAL; + return NM_META_COLOR_CONNECTIVITY_UNKNOWN; } } @@ -155,11 +159,11 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (permission_result_to_string_no_l10n, NMClient NM_UTILS_LOOKUP_ITEM_IGNORE (NM_CLIENT_PERMISSION_RESULT_UNKNOWN), ); -_NM_UTILS_LOOKUP_DEFINE (static, permission_result_to_color, NMClientPermissionResult, NMMetaTermColor, - NM_UTILS_LOOKUP_DEFAULT (NM_META_TERM_COLOR_NORMAL), - NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_YES, NM_META_TERM_COLOR_GREEN), - NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_NO, NM_META_TERM_COLOR_RED), - NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_AUTH, NM_META_TERM_COLOR_YELLOW), +_NM_UTILS_LOOKUP_DEFINE (static, permission_result_to_color, NMClientPermissionResult, NMMetaColor, + NM_UTILS_LOOKUP_DEFAULT (NM_META_COLOR_PERMISSION_UNKNOWN), + NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_YES, NM_META_COLOR_PERMISSION_YES), + NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_NO, NM_META_COLOR_PERMISSION_NO), + NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_AUTH, NM_META_COLOR_PERMISSION_AUTH), NM_UTILS_LOOKUP_ITEM_IGNORE (NM_CLIENT_PERMISSION_RESULT_UNKNOWN), ); @@ -168,14 +172,7 @@ _NM_UTILS_LOOKUP_DEFINE (static, permission_result_to_color, NMClientPermissionR static const NmcMetaGenericInfo *const metagen_general_status[]; static gconstpointer -_metagen_general_status_get_fcn (const NMMetaEnvironment *environment, - gpointer environment_user_data, - const NmcMetaGenericInfo *info, - gpointer target, - NMMetaAccessorGetType get_type, - NMMetaAccessorGetFlags get_flags, - NMMetaAccessorGetOutFlags *out_flags, - gpointer *out_to_free) +_metagen_general_status_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) { NmCli *nmc = target; const char *value; @@ -185,26 +182,26 @@ _metagen_general_status_get_fcn (const NMMetaEnvironment *environment, switch (info->info_type) { case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_RUNNING: - NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL); + NMC_HANDLE_COLOR (NM_META_COLOR_NONE); value = N_("running"); goto translate_and_out; case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_VERSION: - NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL); + NMC_HANDLE_COLOR (NM_META_COLOR_NONE); value = nm_client_get_version (nmc->client); goto clone_and_out; case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STATE: state = nm_client_get_state (nmc->client); - NMC_HANDLE_TERMFORMAT (state_to_color (state)); + NMC_HANDLE_COLOR (state_to_color (state)); value = nm_state_to_string_no_l10n (state); goto translate_and_out; case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STARTUP: v_bool = nm_client_get_startup (nmc->client); - NMC_HANDLE_TERMFORMAT (v_bool ? NM_META_TERM_COLOR_YELLOW : NM_META_TERM_COLOR_GREEN); + NMC_HANDLE_COLOR (v_bool ? NM_META_COLOR_MANAGER_STARTING : NM_META_COLOR_MANAGER_RUNNING); value = v_bool ? N_("starting") : N_("started"); goto translate_and_out; case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_CONNECTIVITY: connectivity = nm_client_get_connectivity (nmc->client); - NMC_HANDLE_TERMFORMAT (connectivity_to_color (connectivity)); + NMC_HANDLE_COLOR (connectivity_to_color (connectivity)); value = nm_connectivity_to_string_no_l10n (connectivity); goto translate_and_out; case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NETWORKING: @@ -233,7 +230,7 @@ _metagen_general_status_get_fcn (const NMMetaEnvironment *environment, g_return_val_if_reached (NULL); enabled_out: - NMC_HANDLE_TERMFORMAT (v_bool ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED); + NMC_HANDLE_COLOR (v_bool ? NM_META_COLOR_ENABLED : NM_META_COLOR_DISABLED); value = v_bool ? N_("enabled") : N_("disabled"); goto translate_and_out; @@ -275,14 +272,7 @@ static const NmcMetaGenericInfo *const metagen_general_status[_NMC_GENERIC_INFO_ /*****************************************************************************/ static gconstpointer -_metagen_general_permissions_get_fcn (const NMMetaEnvironment *environment, - gpointer environment_user_data, - const NmcMetaGenericInfo *info, - gpointer target, - NMMetaAccessorGetType get_type, - NMMetaAccessorGetFlags get_flags, - NMMetaAccessorGetOutFlags *out_flags, - gpointer *out_to_free) +_metagen_general_permissions_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) { NMClientPermission perm = GPOINTER_TO_UINT (target); NmCli *nmc = environment_user_data; @@ -291,11 +281,11 @@ _metagen_general_permissions_get_fcn (const NMMetaEnvironment *environment, switch (info->info_type) { case NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_PERMISSION: - NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL); + NMC_HANDLE_COLOR (NM_META_COLOR_NONE); return permission_to_string (perm); case NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_VALUE: perm_result = nm_client_get_permission_result (nmc->client, perm); - NMC_HANDLE_TERMFORMAT (permission_result_to_color (perm_result)); + NMC_HANDLE_COLOR (permission_result_to_color (perm_result)); s = permission_result_to_string_no_l10n (perm_result); if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) return _(s); @@ -323,21 +313,14 @@ typedef struct { } GetGeneralLoggingData; static gconstpointer -_metagen_general_logging_get_fcn (const NMMetaEnvironment *environment, - gpointer environment_user_data, - const NmcMetaGenericInfo *info, - gpointer target, - NMMetaAccessorGetType get_type, - NMMetaAccessorGetFlags get_flags, - NMMetaAccessorGetOutFlags *out_flags, - gpointer *out_to_free) +_metagen_general_logging_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) { NmCli *nmc = environment_user_data; GetGeneralLoggingData *d = target; nm_assert (info->info_type < _NMC_GENERIC_INFO_TYPE_GENERAL_LOGGING_NUM); - NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL); + NMC_HANDLE_COLOR (NM_META_COLOR_NONE); if (!d->initialized) { d->initialized = TRUE; @@ -513,8 +496,8 @@ show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_fl { gs_free_error GError *error = NULL; const char *fields_str; - const char *fields_all = print_flds ? print_flds : NMC_FIELDS_NM_STATUS_ALL; - const char *fields_common = print_flds ? print_flds : NMC_FIELDS_NM_STATUS_COMMON; + const char *fields_all = print_flds ?: NMC_FIELDS_NM_STATUS_ALL; + const char *fields_common = print_flds ?: NMC_FIELDS_NM_STATUS_COMMON; if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) fields_str = fields_common; @@ -1083,9 +1066,8 @@ networkmanager_running (NMClient *client, GParamSpec *param, NmCli *nmc) char *str; running = nm_client_get_nm_running (client); - str = nmc_colorize (nmc->nmc_config.use_colors, - running ? NM_META_TERM_COLOR_GREEN : NM_META_TERM_COLOR_RED, - NM_META_TERM_FORMAT_NORMAL, + str = nmc_colorize (&nmc->nmc_config, + running ? NM_META_COLOR_MANAGER_RUNNING : NM_META_COLOR_MANAGER_STOPPED, running ? _("NetworkManager has started") : _("NetworkManager has stopped")); g_print ("%s\n", str); g_free (str); @@ -1125,7 +1107,7 @@ client_connectivity (NMClient *client, GParamSpec *param, NmCli *nmc) char *str; g_object_get (client, NM_CLIENT_CONNECTIVITY, &connectivity, NULL); - str = nmc_colorize (nmc->nmc_config.use_colors, connectivity_to_color (connectivity), NM_META_TERM_FORMAT_NORMAL, + str = nmc_colorize (&nmc->nmc_config, connectivity_to_color (connectivity), _("Connectivity is now '%s'\n"), nm_connectivity_to_string (connectivity)); g_print ("%s", str); g_free (str); @@ -1138,14 +1120,13 @@ client_state (NMClient *client, GParamSpec *param, NmCli *nmc) char *str; g_object_get (client, NM_CLIENT_STATE, &state, NULL); - str = nmc_colorize (nmc->nmc_config.use_colors, state_to_color (state), NM_META_TERM_FORMAT_NORMAL, + str = nmc_colorize (&nmc->nmc_config, state_to_color (state), _("Networkmanager is now in the '%s' state\n"), nm_state_to_string (state)); g_print ("%s", str); g_free (str); } - static void device_overview (NmCli *nmc, NMDevice *device) { @@ -1182,12 +1163,12 @@ device_overview (NmCli *nmc, NMDevice *device) if (!nm_device_get_autoconnect (device)) g_string_append_printf (outbuf, "%s, ", _("autoconnect")); if (nm_device_get_firmware_missing (device)) { - tmp = nmc_colorize (nmc->nmc_config.use_colors, NM_META_TERM_COLOR_RED, NM_META_TERM_FORMAT_NORMAL, _("fw missing")); + tmp = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_DEVICE_FIRMWARE_MISSING, _("fw missing")); g_string_append_printf (outbuf, "%s, ", tmp); g_free (tmp); } if (nm_device_get_nm_plugin_missing (device)) { - tmp = nmc_colorize (nmc->nmc_config.use_colors, NM_META_TERM_COLOR_RED, NM_META_TERM_FORMAT_NORMAL, _("plugin missing")); + tmp = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_DEVICE_PLUGIN_MISSING, _("plugin missing")); g_string_append_printf (outbuf, "%s, ", tmp); g_free (tmp); } @@ -1288,7 +1269,7 @@ do_overview (NmCli *nmc, int argc, char **argv) NMDevice **devices; const GPtrArray *p; NMActiveConnection *ac; - NMMetaTermColor color; + NMMetaColor color; NMDnsEntry *dns; char *tmp; int i; @@ -1312,8 +1293,8 @@ do_overview (NmCli *nmc, int argc, char **argv) continue; state = nm_active_connection_get_state (ac); - nmc_active_connection_state_to_color (state, &color); - tmp = nmc_colorize (nmc->nmc_config.use_colors, color, NM_META_TERM_FORMAT_NORMAL, _("%s VPN connection"), + color = nmc_active_connection_state_to_color (state); + tmp = nmc_colorize (&nmc->nmc_config, color, _("%s VPN connection"), nm_active_connection_get_id (ac)); g_print ("%s\n", tmp); g_free (tmp); @@ -1324,14 +1305,13 @@ do_overview (NmCli *nmc, int argc, char **argv) devices = nmc_get_devices_sorted (nmc->client); for (i = 0; devices[i]; i++) { - NMMetaTermFormat color_fmt; NMDeviceState state; ac = nm_device_get_active_connection (devices[i]); state = nm_device_get_state (devices[i]); - nmc_device_state_to_color (state, &color, &color_fmt); - tmp = nmc_colorize (nmc->nmc_config.use_colors, color, color_fmt, "%s: %s%s%s", + color = nmc_device_state_to_color (state); + tmp = nmc_colorize (&nmc->nmc_config, color, "%s: %s%s%s", nm_device_get_iface (devices[i]), nmc_device_state_to_string (state), ac ? " to " : "", @@ -1342,7 +1322,6 @@ do_overview (NmCli *nmc, int argc, char **argv) if (nm_device_get_description (devices[i]) && strcmp (nm_device_get_description (devices[i]), "")) g_print ("\t\"%s\"\n", nm_device_get_description (devices[i])); - device_overview (nmc, devices[i]); if (ac) ac_overview (nmc, ac); @@ -1415,7 +1394,7 @@ do_monitor (NmCli *nmc, int argc, char **argv) if (!nm_client_get_nm_running (nmc->client)) { char *str; - str = nmc_colorize (nmc->nmc_config.use_colors, NM_META_TERM_COLOR_RED, NM_META_TERM_FORMAT_NORMAL, + str = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_MANAGER_STOPPED, _("Networkmanager is not running (waiting for it)\n")); g_print ("%s", str); g_free (str); diff --git a/clients/cli/meson.build b/clients/cli/meson.build new file mode 100644 index 00000000..9449ce63 --- /dev/null +++ b/clients/cli/meson.build @@ -0,0 +1,49 @@ +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 + [ + '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir), + '-DG_LOG_DOMAIN="@0@"'.format(name), + '-DNMLOCALEDIR="@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..e9752952 100644 --- a/clients/cli/nmcli.c +++ b/clients/cli/nmcli.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 2010 - 2017 Red Hat, Inc. + * Copyright 2010 - 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -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" @@ -53,8 +51,67 @@ # define NMCLI_VERSION VERSION #endif -/* Global NmCli object */ -NmCli nm_cli; +NmCli nm_cli = { + .client = NULL, + + .return_value = NMC_RESULT_SUCCESS, + + .timeout = -1, + + .secret_agent = NULL, + .pwds_hash = NULL, + .pk_listener = NULL, + + .should_wait = 0, + .nowait_flag = TRUE, + .nmc_config.print_output = NMC_PRINT_NORMAL, + .nmc_config.multiline_output = FALSE, + .mode_specified = FALSE, + .nmc_config.escape_values = TRUE, + .required_fields = NULL, + .ask = FALSE, + .complete = FALSE, + .nmc_config.show_secrets = FALSE, + .nmc_config.in_editor = FALSE, + .nmc_config.palette = { + [NM_META_COLOR_CONNECTION_ACTIVATED] = "32", + [NM_META_COLOR_CONNECTION_ACTIVATING] = "33", + [NM_META_COLOR_CONNECTION_DISCONNECTING] = "31", + [NM_META_COLOR_CONNECTION_INVISIBLE] = "2", + [NM_META_COLOR_CONNECTIVITY_FULL] = "32", + [NM_META_COLOR_CONNECTIVITY_LIMITED] = "33", + [NM_META_COLOR_CONNECTIVITY_NONE] = "31", + [NM_META_COLOR_CONNECTIVITY_PORTAL] = "33", + [NM_META_COLOR_DEVICE_ACTIVATED] = "32", + [NM_META_COLOR_DEVICE_ACTIVATING] = "33", + [NM_META_COLOR_DEVICE_DISCONNECTED] = "31", + [NM_META_COLOR_DEVICE_FIRMWARE_MISSING] = "31", + [NM_META_COLOR_DEVICE_PLUGIN_MISSING] = "31", + [NM_META_COLOR_DEVICE_UNAVAILABLE] = "2", + [NM_META_COLOR_MANAGER_RUNNING] = "32", + [NM_META_COLOR_MANAGER_STARTING] = "33", + [NM_META_COLOR_MANAGER_STOPPED] = "31", + [NM_META_COLOR_PERMISSION_AUTH] = "33", + [NM_META_COLOR_PERMISSION_NO] = "31", + [NM_META_COLOR_PERMISSION_YES] = "32", + [NM_META_COLOR_STATE_ASLEEP] = "31", + [NM_META_COLOR_STATE_CONNECTED_GLOBAL] = "32", + [NM_META_COLOR_STATE_CONNECTED_LOCAL] = "32", + [NM_META_COLOR_STATE_CONNECTED_SITE] = "32", + [NM_META_COLOR_STATE_CONNECTING] = "33", + [NM_META_COLOR_STATE_DISCONNECTED] = "31", + [NM_META_COLOR_STATE_DISCONNECTING] = "33", + [NM_META_COLOR_WIFI_SIGNAL_EXCELLENT] = "32", + [NM_META_COLOR_WIFI_SIGNAL_FAIR] = "35", + [NM_META_COLOR_WIFI_SIGNAL_GOOD] = "33", + [NM_META_COLOR_WIFI_SIGNAL_POOR] = "36", + [NM_META_COLOR_WIFI_SIGNAL_UNKNOWN] = "2", + [NM_META_COLOR_ENABLED] = "32", + [NM_META_COLOR_DISABLED] = "31", + }, + .editor_status_line = FALSE, + .editor_save_confirmation = TRUE, +}; /*****************************************************************************/ @@ -129,9 +186,8 @@ complete_fields (const char *option, const char *prefix) h = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL); complete_field (h, metagen_ip4_config); - complete_field (h, nmc_fields_dhcp4_config); + complete_field (h, nmc_fields_dhcp_config); complete_field (h, nmc_fields_ip6_config); - complete_field (h, nmc_fields_dhcp6_config); complete_field (h, nmc_fields_con_show); complete_field (h, nmc_fields_con_active_details_general); complete_field (h, nmc_fields_con_active_details_vpn); @@ -186,6 +242,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" @@ -272,9 +329,299 @@ matches_arg (NmCli *nmc, int *argc, char ***argv, const char *pattern, char **ar return TRUE; } +/*************************************************************************************/ + +typedef enum { + NMC_USE_COLOR_AUTO, + NMC_USE_COLOR_YES, + NMC_USE_COLOR_NO, +} NmcColorOption; + +/* Checks whether a particular terminal-colors.d(5) file (.enabled, .disabled or .schem) + * exists. If contents is non-NULL, it returns the content. */ +static gboolean +check_colors_file (NmCli *nmc, NmcColorOption *color_option, + const char *base_dir, const char *name, const char *term, const char *type, + char **contents) +{ + char *filename; + gboolean exists; + + filename = g_strdup_printf ("%s/terminal-colors.d/%s%s%s%s%s", + base_dir, + name ? name : "", + term ? "@" : "", term ? term : "", + (name || term) ? "." : "", + type); + if (contents) + exists = g_file_get_contents (filename, contents, NULL, NULL); + else + exists = g_file_test (filename, G_FILE_TEST_EXISTS); + g_free (filename); + + return exists; +} + +static void +check_colors_files_for_term (NmCli *nmc, NmcColorOption *color_option, + const char *base_dir, const char *name, const char *term) +{ + if ( *color_option == NMC_USE_COLOR_AUTO + && check_colors_file (nmc, color_option, base_dir, name, term, "enable", NULL)) { + *color_option = NMC_USE_COLOR_YES; + } + + if ( *color_option == NMC_USE_COLOR_AUTO + && check_colors_file (nmc, color_option, base_dir, name, term, "disable", NULL)) { + *color_option = NMC_USE_COLOR_NO; + } + + if (*color_option == NMC_USE_COLOR_NO) { + /* No need to bother any further. */ + return; + } + + if (nmc->palette_buffer == NULL) + check_colors_file (nmc, color_option, base_dir, name, term, "schem", &nmc->palette_buffer); +} + +static void +check_colors_files_for_name (NmCli *nmc, NmcColorOption *color_option, + const char *base_dir, const char *name) +{ + const gchar *term; + + /* Take a shortcut if the directory is not there. */ + if (!g_file_test (base_dir, G_FILE_TEST_EXISTS)) + return; + + term = g_getenv ("TERM"); + if (term) + check_colors_files_for_term (nmc, color_option, base_dir, name, term); + check_colors_files_for_term (nmc, color_option, base_dir, name, NULL); +} + +static void +check_colors_files_for_base_dir (NmCli *nmc, NmcColorOption *color_option, + const char *base_dir) +{ + check_colors_files_for_name (nmc, color_option, base_dir, "nmcli"); + check_colors_files_for_name (nmc, color_option, base_dir, NULL); +} + +static const char * +resolve_color_alias (const char *color) +{ + static const struct { + const char *name; + const char *alias; + } aliases[] = { + { "reset", "0" }, + { "bold", "1" }, + { "white", "1;37" }, + { "halfbright", "2" }, + { "underscore", "4" }, + { "blink", "5" }, + { "reverse", "7" }, + { "black", "30" }, + { "red", "31" }, + { "green", "32" }, + { "brown", "33" }, + { "yellow", "33" }, /* well, yellow */ + { "blue", "34" }, + { "magenta", "35" }, + { "cyan", "36" }, + { "gray", "37" }, + { "darkgray", "90" }, + { "lightred", "91" }, + { "lightgreen", "92" }, + { "lightblue", "94" }, + { "lightmagenta", "95" }, + { "lightcyan", "96" }, + { "lightgray", "97" }, + }; + int i; + + /* Shortcut literal sequences. */ + if (g_ascii_isdigit (*color)) + return color; + + for (i = 0; i < G_N_ELEMENTS (aliases); i++) { + if (strcmp (color, aliases[i].name) == 0) + return aliases[i].alias; + } + + return color; +} + +static gboolean +parse_color_scheme (NmCli *nmc, GError **error) +{ + char *p = nmc->palette_buffer; + const char *name; + const char *color; + const char *map[_NM_META_COLOR_NUM] = { + [NM_META_COLOR_NONE] = NULL, + [NM_META_COLOR_CONNECTION_ACTIVATED] = "connection-activated", + [NM_META_COLOR_CONNECTION_ACTIVATING] = "connection-activating", + [NM_META_COLOR_CONNECTION_DISCONNECTING] = "connection-disconnecting", + [NM_META_COLOR_CONNECTION_INVISIBLE] = "connection-invisible", + [NM_META_COLOR_CONNECTION_UNKNOWN] = "connection-unknown", + [NM_META_COLOR_CONNECTIVITY_FULL] = "connectivity-full", + [NM_META_COLOR_CONNECTIVITY_LIMITED] = "connectivity-limited", + [NM_META_COLOR_CONNECTIVITY_NONE] = "connectivity-none", + [NM_META_COLOR_CONNECTIVITY_PORTAL] = "connectivity-portal", + [NM_META_COLOR_CONNECTIVITY_UNKNOWN] = "connectivity-unknown", + [NM_META_COLOR_DEVICE_ACTIVATED] = "device-activated", + [NM_META_COLOR_DEVICE_ACTIVATING] = "device-activating", + [NM_META_COLOR_DEVICE_DISCONNECTED] = "device-disconnected", + [NM_META_COLOR_DEVICE_FIRMWARE_MISSING] = "device-firmware-missing", + [NM_META_COLOR_DEVICE_PLUGIN_MISSING] = "device-plugin-missing", + [NM_META_COLOR_DEVICE_UNAVAILABLE] = "device-unavailable", + [NM_META_COLOR_DEVICE_UNKNOWN] = "device-unknown", + [NM_META_COLOR_MANAGER_RUNNING] = "manager-running", + [NM_META_COLOR_MANAGER_STARTING] = "manager-starting", + [NM_META_COLOR_MANAGER_STOPPED] = "manager-stopped", + [NM_META_COLOR_PERMISSION_AUTH] = "permission-auth", + [NM_META_COLOR_PERMISSION_NO] = "permission-no", + [NM_META_COLOR_PERMISSION_UNKNOWN] = "permission-unknown", + [NM_META_COLOR_PERMISSION_YES] = "permission-yes", + [NM_META_COLOR_PROMPT] = "prompt", + [NM_META_COLOR_STATE_ASLEEP] = "state-asleep", + [NM_META_COLOR_STATE_CONNECTED_GLOBAL] = "state-connected-global", + [NM_META_COLOR_STATE_CONNECTED_LOCAL] = "state-connected-local", + [NM_META_COLOR_STATE_CONNECTED_SITE] = "state-connected-site", + [NM_META_COLOR_STATE_CONNECTING] = "state-connecting", + [NM_META_COLOR_STATE_DISCONNECTED] = "state-disconnected", + [NM_META_COLOR_STATE_DISCONNECTING] = "state-disconnecting", + [NM_META_COLOR_STATE_UNKNOWN] = "state-unknown", + [NM_META_COLOR_WIFI_SIGNAL_EXCELLENT] = "wifi-signal-excellent", + [NM_META_COLOR_WIFI_SIGNAL_FAIR] = "wifi-signal-fair", + [NM_META_COLOR_WIFI_SIGNAL_GOOD] = "wifi-signal-good", + [NM_META_COLOR_WIFI_SIGNAL_POOR] = "wifi-signal-poor", + [NM_META_COLOR_WIFI_SIGNAL_UNKNOWN] = "wifi-signal-unknown", + [NM_META_COLOR_DISABLED] = "disabled", + [NM_META_COLOR_ENABLED] = "enabled", + }; + int i; + + /* This reads through the raw color scheme file contents, identifying the + * color names and sequences, putting in terminating NULs in place, so that + * pointers into the buffer can readily be used as strings in the palette. */ + while (1) { + /* Leading whitespace. */ + while (nm_utils_is_separator (*p) || *p == '\n') + p++; + + if (*p == '\0') + break; + + /* Comments. */ + if (*p == '#') { + while (*p != '\n' && *p != '\0') + p++; + continue; + } + + /* Color name. */ + name = p; + while (g_ascii_isgraph (*p)) + p++; + if (*p == '\0') { + g_set_error (error, NMCLI_ERROR, 0, + _("Unexpected end of file following '%s'\n"), name); + return FALSE; + } + + /* Separating whitespace. */ + if (!nm_utils_is_separator (*p)) { + *p = '\0'; + g_set_error (error, NMCLI_ERROR, 0, + _("Expected whitespace following '%s'\n"), name); + return FALSE; + } + while (nm_utils_is_separator (*p)) { + *p = '\0'; + p++; + } + + /* Color sequence. */ + color = p; + if (!g_ascii_isgraph (*p)) { + g_set_error (error, NMCLI_ERROR, 0, + _("Expected a value for '%s'\n"), name); + return FALSE; + } + while (g_ascii_isgraph (*p)) + p++; + + /* Trailing whitespace. */ + while (nm_utils_is_separator (*p)) { + *p = '\0'; + p++; + } + if (*p != '\0') { + if (*p != '\n') { + g_set_error (error, NMCLI_ERROR, 0, + _("Expected a line break following '%s'\n"), color); + return FALSE; + } + *p = '\0'; + p++; + } + + /* All good, set the palette entry. */ + for (i = NM_META_COLOR_NONE + 1; i < _NM_META_COLOR_NUM; i++) { + if (strcmp (map[i], name) == 0) { + nmc->nmc_config_mutable.palette[i] = resolve_color_alias (color); + break; + } + } + if (i == _NM_META_COLOR_NUM) + g_debug ("Ignoring an unrecognized color: '%s'\n", name); + } + + return TRUE; +} + +static void +set_colors (NmCli *nmc, NmcColorOption color_option) +{ + GError *error = NULL; + + if (color_option == NMC_USE_COLOR_AUTO) { + if ( g_strcmp0 (g_getenv ("TERM"), "dumb") == 0 + || !isatty (STDOUT_FILENO)) + color_option = NMC_USE_COLOR_NO; + } + + check_colors_files_for_base_dir (nmc, &color_option, g_get_user_config_dir ()); + check_colors_files_for_base_dir (nmc, &color_option, SYSCONFDIR); + + switch (color_option) { + case NMC_USE_COLOR_YES: + case NMC_USE_COLOR_AUTO: + nmc->nmc_config_mutable.use_colors = TRUE; + break; + case NMC_USE_COLOR_NO: + nmc->nmc_config_mutable.use_colors = FALSE; + break; + } + + if (nmc->nmc_config_mutable.use_colors && nmc->palette_buffer) { + if (!parse_color_scheme (nmc, &error)) { + g_debug ("Error parsing color scheme: %s", error->message); + g_error_free (error); + } + } +} + +/*************************************************************************************/ + static gboolean process_command_line (NmCli *nmc, int argc, char **argv) { + NmcColorOption colors = NMC_USE_COLOR_AUTO; char *base; base = strrchr (argv[0], '/'); @@ -297,9 +644,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 +656,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; @@ -351,11 +701,11 @@ process_command_line (NmCli *nmc, int argc, char **argv) if (argc == 1 && nmc->complete) complete_option_with_value (argv[0], value, "yes", "no", "auto", NULL); if (matches (value, "auto")) - nmc->nmc_config_mutable.use_colors = NMC_USE_COLOR_AUTO; + colors = NMC_USE_COLOR_AUTO; else if (matches (value, "yes")) - nmc->nmc_config_mutable.use_colors = NMC_USE_COLOR_YES; + colors = NMC_USE_COLOR_YES; else if (matches (value, "no")) - nmc->nmc_config_mutable.use_colors = NMC_USE_COLOR_NO; + colors = NMC_USE_COLOR_NO; else { g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), value, argv[0]); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; @@ -382,8 +732,8 @@ process_command_line (NmCli *nmc, int argc, char **argv) complete_fields (argv[0], value); nmc->required_fields = g_strdup (value); nmc->nmc_config_mutable.print_output = NMC_PRINT_TERSE; - /* We want fixed tabular mode here, but just set the mode specified and rely on the initialization - * in nmc_init: in this way we allow use of "-m multiline" to swap the output mode also if placed + /* We want fixed tabular mode here, but just set the mode specified and rely on defaults: + * in this way we allow use of "-m multiline" to swap the output mode also if placed * before the "-g <field>" option (-g may be still more practical and easy to remember than -t -f). */ nmc->mode_specified = TRUE; @@ -417,6 +767,12 @@ 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; + + set_colors (nmc, colors); + /* Now run the requested command */ nmc_do_cmd (nmc, nmcli_cmds, *argv, argc, argv); @@ -553,38 +909,6 @@ nmc_value_transforms_register (void) nmc_convert_bytes_to_string); } -/* Initialize NmCli structure - set default values */ -static void -nmc_init (NmCli *nmc) -{ - nmc->client = NULL; - - nmc->return_value = NMC_RESULT_SUCCESS; - nmc->return_text = g_string_new (_("Success")); - - nmc->timeout = -1; - - nmc->secret_agent = NULL; - nmc->pwds_hash = NULL; - nmc->pk_listener = NULL; - - nmc->should_wait = 0; - nmc->nowait_flag = TRUE; - nmc->nmc_config_mutable.print_output = NMC_PRINT_NORMAL; - nmc->nmc_config_mutable.multiline_output = FALSE; - nmc->mode_specified = FALSE; - nmc->nmc_config_mutable.escape_values = TRUE; - nmc->required_fields = NULL; - nmc->ask = FALSE; - nmc->complete = FALSE; - nmc->nmc_config_mutable.show_secrets = FALSE; - nmc->nmc_config_mutable.use_colors = NMC_USE_COLOR_AUTO; - nmc->nmc_config_mutable.in_editor = FALSE; - nmc->editor_status_line = FALSE; - nmc->editor_save_confirmation = TRUE; - nmc->editor_prompt_color = NM_META_TERM_COLOR_NORMAL; -} - static void nmc_cleanup (NmCli *nmc) { @@ -602,7 +926,7 @@ nmc_cleanup (NmCli *nmc) if (nmc->pwds_hash) g_hash_table_destroy (nmc->pwds_hash); - g_free (nmc->required_fields); + nm_clear_g_free (&nmc->required_fields); if (nmc->pager_pid > 0) { fclose (stdout); @@ -613,6 +937,8 @@ nmc_cleanup (NmCli *nmc) nmc->pager_pid = 0; } + nm_clear_g_free (&nmc->palette_buffer); + nmc_polkit_agent_fini (nmc); } @@ -624,19 +950,17 @@ main (int argc, char *argv[]) #ifdef GETTEXT_PACKAGE /* Set i18n stuff */ - bindtextdomain (GETTEXT_PACKAGE, NMCLI_LOCALEDIR); + bindtextdomain (GETTEXT_PACKAGE, NMLOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); #endif - nm_g_type_init (); - /* Save terminal settings */ tcgetattr (STDIN_FILENO, &termios_orig); nmc_value_transforms_register (); - nmc_init (&nm_cli); + nm_cli.return_text = g_string_new (_("Success")); loop = g_main_loop_new (NULL, FALSE); g_unix_signal_add (SIGTERM, signal_handler, GINT_TO_POINTER (SIGTERM)); diff --git a/clients/cli/nmcli.h b/clients/cli/nmcli.h index 874bca21..61bf86de 100644 --- a/clients/cli/nmcli.h +++ b/clients/cli/nmcli.h @@ -14,23 +14,16 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2010 - 2017 Red Hat, Inc. + * Copyright 2010 - 2018 Red Hat, Inc. */ #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); @@ -100,23 +93,18 @@ struct _NmcOutputField { gboolean value_is_array; /* Whether value is char** instead of char* */ gboolean free_value; /* Whether to free the value */ NmcOfFlags flags; /* Flags - whether and how to print values/field names/headers */ - NMMetaTermColor color; /* Use this color to print value */ - NMMetaTermFormat color_fmt; /* Use this terminal format to print value */ + NMMetaColor color; /* Use this color to print value */ }; -typedef enum { - NMC_USE_COLOR_AUTO, - NMC_USE_COLOR_YES, - NMC_USE_COLOR_NO, -} NmcColorOption; - typedef struct _NmcConfig { NMCPrintOutput print_output; /* Output mode */ - NmcColorOption use_colors; /* Whether to use colors for output: option '--color' */ + gboolean use_colors; /* Whether to use colors for output: option '--color' */ bool multiline_output; /* Multiline output instead of default tabular */ 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) */ + const char *palette[_NM_META_COLOR_NUM]; /* Color palette */ } NmcConfig; typedef struct _NmcOutputData { @@ -135,7 +123,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 */ @@ -149,9 +137,15 @@ typedef struct _NmCli { gboolean complete; /* Autocomplete the command line */ gboolean editor_status_line; /* Whether to display status line in connection editor */ gboolean editor_save_confirmation; /* Whether to ask for confirmation on saving connections with 'autoconnect=yes' */ - NMMetaTermColor editor_prompt_color; /* Color of prompt in connection editor */ + + char *palette_buffer; /* Buffer with sequences for terminal-colors.d(5)-based coloring. */ } NmCli; +#define NMC_RETURN(nmc, rvalue) \ + G_STMT_START { \ + return ((nmc)->return_value = (rvalue)); \ + } G_STMT_END + extern NmCli nm_cli; /* Error quark for GError domain */ 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..01142ba2 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); @@ -746,9 +749,9 @@ nmc_setting_get_property_desc (NMSetting *setting, const char *prop) return g_strdup_printf ("%s\n%s\n%s%s%s%s", setting_desc_title, - setting_desc ? setting_desc : "", + setting_desc ?: "", nmcli_nl, nmcli_desc_title, nmcli_nl, - nmcli_desc ? nmcli_desc : ""); + nmcli_desc ?: ""); } /* diff --git a/clients/cli/utils.c b/clients/cli/utils.c index f20e24ce..32c44e39 100644 --- a/clients/cli/utils.c +++ b/clients/cli/utils.c @@ -15,7 +15,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright 2010 Lennart Poettering - * Copyright 2010 - 2017 Red Hat, Inc. + * Copyright 2010 - 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -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; @@ -85,23 +86,25 @@ _meta_type_nmc_generic_info_get_fcn (const NMMetaAbstractInfo *abstract_info, if (!NM_IN_SET (get_type, NM_META_ACCESSOR_GET_TYPE_PARSABLE, NM_META_ACCESSOR_GET_TYPE_PRETTY, - NM_META_ACCESSOR_GET_TYPE_TERMFORMAT)) + NM_META_ACCESSOR_GET_TYPE_COLOR)) g_return_val_if_reached (NULL); - /* omitting the out_to_free value is only allowed for TERMFORMAT. */ - nm_assert (out_to_free || NM_IN_SET (get_type, NM_META_ACCESSOR_GET_TYPE_TERMFORMAT)); + /* omitting the out_to_free value is only allowed for COLOR. */ + nm_assert (out_to_free || NM_IN_SET (get_type, NM_META_ACCESSOR_GET_TYPE_COLOR)); if (info->get_fcn) { - return info->get_fcn (environment, environment_user_data, + return info->get_fcn (environment, + environment_user_data, info, target, get_type, get_flags, out_flags, + out_is_default, out_to_free); } if (info->nested) { - NMC_HANDLE_TERMFORMAT (NM_META_TERM_COLOR_NORMAL); + NMC_HANDLE_COLOR (NM_META_COLOR_NONE); return info->name; } @@ -117,37 +120,16 @@ const NMMetaType nmc_meta_type_generic_info = { /*****************************************************************************/ -static gboolean -use_colors (NmcColorOption color_option) -{ - if (color_option == NMC_USE_COLOR_AUTO) { - static NmcColorOption cached = NMC_USE_COLOR_AUTO; - - if (G_UNLIKELY (cached == NMC_USE_COLOR_AUTO)) { - if ( g_strcmp0 (g_getenv ("TERM"), "dumb") == 0 - || !isatty (STDOUT_FILENO)) - cached = NMC_USE_COLOR_NO; - else - cached = NMC_USE_COLOR_YES; - } - return cached == NMC_USE_COLOR_YES; - } - - return color_option == NMC_USE_COLOR_YES; -} - static const char * -colorize_string (NmcColorOption color_option, - NMMetaTermColor color, - NMMetaTermFormat color_fmt, +colorize_string (const NmcConfig *nmc_config, + NMMetaColor color, const char *str, char **out_to_free) { const char *out = str; - if ( use_colors (color_option) - && (color != NM_META_TERM_COLOR_NORMAL || color_fmt != NM_META_TERM_FORMAT_NORMAL)) { - *out_to_free = nmc_colorize (color_option, color, color_fmt, "%s", str); + if (nmc_config && nmc_config->use_colors) { + *out_to_free = nmc_colorize (nmc_config, color, "%s", str); out = *out_to_free; } @@ -202,7 +184,6 @@ next_arg (NmCli *nmc, int *argc, char ***argv, ...) if (*argc == 0) return -1; - va_start (args, argv); if (nmc && nmc->complete && *argc == 1) { @@ -389,118 +370,30 @@ nmc_terminal_show_progress (const char *str) const char slashes[4] = {'|', '/', '-', '\\'}; nmc_terminal_erase_line (); - g_print ("%c %s", slashes[idx++], str ? str : ""); + g_print ("%c %s", slashes[idx++], str ?: ""); fflush (stdout); if (idx == 4) idx = 0; } -const char * -nmc_term_color_sequence (NMMetaTermColor color) -{ - switch (color) { - case NM_META_TERM_COLOR_BLACK: - return "\33[30m"; - break; - case NM_META_TERM_COLOR_RED: - return "\33[31m"; - break; - case NM_META_TERM_COLOR_GREEN: - return "\33[32m"; - break; - case NM_META_TERM_COLOR_YELLOW: - return "\33[33m"; - break; - case NM_META_TERM_COLOR_BLUE: - return "\33[34m"; - break; - case NM_META_TERM_COLOR_MAGENTA: - return "\33[35m"; - break; - case NM_META_TERM_COLOR_CYAN: - return "\33[36m"; - break; - case NM_META_TERM_COLOR_WHITE: - return "\33[37m"; - break; - default: - return ""; - break; - } -} - -/* Parses @str for color as string or number */ -NMMetaTermColor -nmc_term_color_parse_string (const char *str, GError **error) -{ - unsigned long color_int; - static const char *colors[] = { "normal", "black", "red", "green", "yellow", - "blue", "magenta", "cyan", "white", NULL }; - - if (nmc_string_to_uint (str, TRUE, 0, 8, &color_int)) { - return (NMMetaTermColor) color_int; - } else { - const char *color, **p; - int i; - - color = nmc_string_is_valid (str, colors, error); - for (p = colors, i = 0; *p != NULL; p++, i++) { - if (*p == color) - return (NMMetaTermColor) i; - } - return -1; - } -} - -const char * -nmc_term_format_sequence (NMMetaTermFormat format) -{ - switch (format) { - case NM_META_TERM_FORMAT_BOLD: - return "\33[1m"; - break; - case NM_META_TERM_FORMAT_DIM: - return "\33[2m"; - break; - case NM_META_TERM_FORMAT_UNDERLINE: - return "\33[4m"; - break; - case NM_META_TERM_FORMAT_BLINK: - return "\33[5m"; - break; - case NM_META_TERM_FORMAT_REVERSE: - return "\33[7m"; - break; - case NM_META_TERM_FORMAT_HIDDEN: - return "\33[8m"; - break; - default: - return ""; - break; - } -} - char * -nmc_colorize (NmcColorOption color_option, NMMetaTermColor color, NMMetaTermFormat format, const char *fmt, ...) +nmc_colorize (const NmcConfig *nmc_config, NMMetaColor color, const char *fmt, ...) { va_list args; char *str, *colored; - const char *ansi_color, *color_end, *ansi_fmt, *format_end; - static const char *end_seq = "\33[0m"; + const char *ansi_seq = NULL; va_start (args, fmt); str = g_strdup_vprintf (fmt, args); va_end (args); - if (!use_colors (color_option)) - return str; + if (nmc_config->use_colors) + ansi_seq = nmc_config->palette[color]; - ansi_color = nmc_term_color_sequence (color); - ansi_fmt = nmc_term_format_sequence (format); - color_end = *ansi_color ? end_seq : ""; - format_end = *ansi_fmt ? end_seq : ""; + if (ansi_seq == NULL) + return str; - colored = g_strdup_printf ("%s%s%s%s%s", ansi_fmt, ansi_color, str, color_end, format_end); + colored = g_strdup_printf ("\33[%sm%s\33[0m", ansi_seq, str); g_free (str); return colored; } @@ -524,7 +417,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 +496,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 +511,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 +526,6 @@ nmc_string_to_arg_array (const char *line, const char *delim, gboolean unquote, *argv = arr; *argc = g_strv_length (arr); - return 0; } @@ -713,7 +610,7 @@ set_val_arrc (NmcOutputField fields_array[], guint32 idx, const char **value) } void -set_val_color_all (NmcOutputField fields_array[], NMMetaTermColor color) +set_val_color_all (NmcOutputField fields_array[], NMMetaColor color) { int i; @@ -722,16 +619,6 @@ set_val_color_all (NmcOutputField fields_array[], NMMetaTermColor color) } } -void -set_val_color_fmt_all (NmcOutputField fields_array[], NMMetaTermFormat format) -{ - int i; - - for (i = 0; fields_array[i].info; i++) { - fields_array[i].color_fmt = format; - } -} - /* * Free 'value' members in array of NmcOutputField */ @@ -998,6 +885,7 @@ typedef struct { const PrintDataCol *col; const char *title; bool title_to_free:1; + bool skip:1; int width; } PrintDataHeaderCell; @@ -1009,8 +897,7 @@ typedef enum { typedef struct { guint row_idx; const PrintDataHeaderCell *header_cell; - NMMetaTermColor term_color; - NMMetaTermFormat term_format; + NMMetaColor color; union { const char *plain; const char *const*strv; @@ -1096,6 +983,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 +1018,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 +1037,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) { @@ -1167,16 +1060,15 @@ _print_fill (const NmcConfig *nmc_config, cell->text_to_free = !!to_free; } - nm_meta_termformat_unpack (nm_meta_abstract_info_get (info, - nmc_meta_environment, - nmc_meta_environment_arg, - target, - NM_META_ACCESSOR_GET_TYPE_TERMFORMAT, - NM_META_ACCESSOR_GET_FLAGS_NONE, - &color_out_flags, - NULL), - &cell->term_color, - &cell->term_format); + cell->color = GPOINTER_TO_INT (nm_meta_abstract_info_get (info, + nmc_meta_environment, + nmc_meta_environment_arg, + target, + NM_META_ACCESSOR_GET_TYPE_COLOR, + NM_META_ACCESSOR_GET_FLAGS_NONE, + &color_out_flags, + NULL, + NULL)); if (cell->text_format == PRINT_DATA_CELL_FORMAT_TYPE_PLAIN) { if (pretty && (!cell->text.plain|| !cell->text.plain[0])) { @@ -1231,6 +1123,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. */ @@ -1358,9 +1253,7 @@ _print_do (const NmcConfig *nmc_config, gs_free char *text_to_free = NULL; const char *text; - text = colorize_string (nmc_config->use_colors, - cell->term_color, cell->term_format, - lines[i_lines], &text_to_free); + text = colorize_string (nmc_config, cell->color, lines[i_lines], &text_to_free); if (multiline) { gs_free char *prefix = NULL; @@ -1408,8 +1301,7 @@ _print_do (const NmcConfig *nmc_config, } if ( pretty - && ( i_row < row_len - 1 - || multiline)) { + && multiline) { gs_free char *line = NULL; g_print ("%s\n", (line = g_strnfill (ML_HEADER_WIDTH, '-'))); @@ -1489,7 +1381,7 @@ nmc_terminal_spawn_pager (const NmcConfig *nmc_config) if ( nm_cli.nmc_config.in_editor || nm_cli.pager_pid > 0 || nmc_config->print_output == NMC_PRINT_TERSE - || !use_colors (nmc_config->use_colors) + || !nmc_config->use_colors || g_strcmp0 (pager, "") == 0 || getauxval (AT_SECURE)) return; @@ -1560,7 +1452,7 @@ nmc_terminal_spawn_pager (const NmcConfig *nmc_config) /*****************************************************************************/ static const char * -get_value_to_print (NmcColorOption color_option, +get_value_to_print (const NmcConfig *nmc_config, const NmcOutputField *field, gboolean field_name, const char *not_set_str, @@ -1586,7 +1478,7 @@ get_value_to_print (NmcColorOption color_option, } /* colorize the value */ - out = colorize_string (color_option, field->color, field->color_fmt, value, out_to_free); + out = colorize_string (nmc_config, field->color, value, out_to_free); if (out && out == free_value) { nm_assert (!*out_to_free); @@ -1680,7 +1572,7 @@ print_required_fields (const NmcConfig *nmc_config, gs_free char *tmp = NULL; val = *p ?: not_set_str; - print_val = colorize_string (nmc_config->use_colors, field_values[idx].color, field_values[idx].color_fmt, + print_val = colorize_string (nmc_config, field_values[idx].color, val, &val_to_free); tmp = g_strdup_printf ("%s%s%s[%d]:", section_prefix ? (const char*) field_values[0].value : "", @@ -1701,7 +1593,7 @@ print_required_fields (const NmcConfig *nmc_config, /* value is a string */ val = val && *val ? val : not_set_str; - print_val = colorize_string (nmc_config->use_colors, field_values[idx].color, field_values[idx].color_fmt, + print_val = colorize_string (nmc_config, field_values[idx].color, val, &val_to_free); tmp = g_strdup_printf ("%s%s%s:", section_prefix ? hdr_name : "", @@ -1732,7 +1624,7 @@ print_required_fields (const NmcConfig *nmc_config, idx = g_array_index (indices, int, i); - value = get_value_to_print (nmc_config->use_colors, (NmcOutputField *) field_values+idx, field_names, + value = get_value_to_print (nmc_config, (NmcOutputField *) field_values+idx, field_names, not_set_str, &val_to_free); if (terse) { @@ -1805,7 +1697,7 @@ print_data_prepare_width (GPtrArray *output_data) row = g_ptr_array_index (output_data, j); field_names = row[0].flags & NMC_OF_FLAG_FIELD_NAMES; - value = get_value_to_print (NMC_USE_COLOR_NO, row+i, field_names, "--", &val_to_free); + value = get_value_to_print (NULL, row+i, field_names, "--", &val_to_free); len = nmc_string_screen_width (value, NULL); max_width = len > max_width ? len : max_width; } diff --git a/clients/cli/utils.h b/clients/cli/utils.h index ffc5b6f3..dc0ce083 100644 --- a/clients/cli/utils.h +++ b/clients/cli/utils.h @@ -14,7 +14,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2010 - 2017 Red Hat, Inc. + * Copyright 2010 - 2018 Red Hat, Inc. */ #ifndef NMC_UTILS_H @@ -41,11 +41,7 @@ char *ssid_to_hex (const char *str, gsize len); void nmc_terminal_erase_line (void); void nmc_terminal_show_progress (const char *str); void nmc_terminal_spawn_pager (const NmcConfig *nmc_config); -gboolean nmc_term_use_colors (NmcColorOption color_option); -const char *nmc_term_color_sequence (NMMetaTermColor color); -const char *nmc_term_format_sequence (NMMetaTermFormat format); -NMMetaTermColor nmc_term_color_parse_string (const char *str, GError **error); -char *nmc_colorize (NmcColorOption color_option, NMMetaTermColor color, NMMetaTermFormat format, const char * fmt, ...) _nm_printf (4, 5); +char *nmc_colorize (const NmcConfig *nmc_config, NMMetaColor color, const char * fmt, ...) _nm_printf (3, 4); void nmc_filter_out_colors_inplace (char *str); char *nmc_filter_out_colors (const char *str); char *nmc_get_user_input (const char *ask_str); @@ -53,14 +49,12 @@ 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); void set_val_arr (NmcOutputField fields_array[], guint32 index, char **value); void set_val_arrc (NmcOutputField fields_array[], guint32 index, const char **value); -void set_val_color_all (NmcOutputField fields_array[], NMMetaTermColor color); -void set_val_color_fmt_all (NmcOutputField fields_array[], NMMetaTermFormat format); +void set_val_color_all (NmcOutputField fields_array[], NMMetaColor color); void nmc_free_output_field_values (NmcOutputField fields_array[]); GArray *parse_output_fields (const char *fields_str, @@ -129,10 +123,10 @@ typedef enum { } NmcGenericInfoType; -#define NMC_HANDLE_TERMFORMAT(color) \ +#define NMC_HANDLE_COLOR(color) \ G_STMT_START { \ - if (get_type == NM_META_ACCESSOR_GET_TYPE_TERMFORMAT) \ - return nm_meta_termformat_pack ((color), NM_META_TERM_FORMAT_NORMAL); \ + if (get_type == NM_META_ACCESSOR_GET_TYPE_COLOR) \ + return GINT_TO_POINTER (color); \ } G_STMT_END struct _NmcMetaGenericInfo { @@ -144,14 +138,19 @@ struct _NmcMetaGenericInfo { const char *name; const char *name_header; const NmcMetaGenericInfo *const*nested; - gconstpointer (*get_fcn) (const NMMetaEnvironment *environment, - gpointer environment_user_data, - const NmcMetaGenericInfo *info, - gpointer target, - NMMetaAccessorGetType get_type, - NMMetaAccessorGetFlags get_flags, - NMMetaAccessorGetOutFlags *out_flags, - gpointer *out_to_free); + +#define NMC_META_GENERIC_INFO_GET_FCN_ARGS \ + const NMMetaEnvironment *environment, \ + gpointer environment_user_data, \ + const NmcMetaGenericInfo *info, \ + gpointer target, \ + NMMetaAccessorGetType get_type, \ + NMMetaAccessorGetFlags get_flags, \ + NMMetaAccessorGetOutFlags *out_flags, \ + gboolean *out_is_default, \ + gpointer *out_to_free + + gconstpointer (*get_fcn) (NMC_META_GENERIC_INFO_GET_FCN_ARGS); }; #define NMC_META_GENERIC(n, ...) \ @@ -164,6 +163,52 @@ struct _NmcMetaGenericInfo { #define NMC_META_GENERIC_WITH_NESTED(n, nest, ...) \ NMC_META_GENERIC (n, .nested = (nest), __VA_ARGS__) +#define NMC_META_GENERIC_GROUP(_group_name, _nested, _name_header) \ + ((const NMMetaAbstractInfo *const*) ((const NmcMetaGenericInfo *const[]) { \ + NMC_META_GENERIC_WITH_NESTED (_group_name,_nested, .name_header = _name_header), \ + NULL, \ + })) + +static inline const char * +nmc_meta_generic_get_str_i18n (const char *s, NMMetaAccessorGetType get_type) +{ + if (!NM_IN_SET (get_type, NM_META_ACCESSOR_GET_TYPE_PRETTY, + NM_META_ACCESSOR_GET_TYPE_PARSABLE)) + g_return_val_if_reached (NULL); + + if (!s) + return NULL; + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) + return gettext (s); + return s; +} + +static inline const char * +nmc_meta_generic_get_bool (gboolean val, NMMetaAccessorGetType get_type) +{ + return nmc_meta_generic_get_str_i18n (val ? N_("yes") : N_("no"), get_type); +} + +static inline char * +nmc_meta_generic_get_enum_with_detail (gint64 enum_val, const char *str_val, NMMetaAccessorGetType get_type) +{ + if (!NM_IN_SET (get_type, NM_META_ACCESSOR_GET_TYPE_PRETTY, + NM_META_ACCESSOR_GET_TYPE_PARSABLE)) + g_return_val_if_reached (NULL); + + if (!str_val) { + /* Pass %NULL for only printing the numeric value. */ + return g_strdup_printf ("%lld", (long long) enum_val); + } + + /* note that this function will always print "$NUM ($NICK)", also in PARSABLE + * mode. That might not be desired, but it's done for certain properties to preserve + * previous behavior. */ + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) + return g_strdup_printf (_("%lld (%s)"), (long long) enum_val, gettext (str_val)); + return g_strdup_printf ("%lld (%s)", (long long) enum_val, str_val); +} + /*****************************************************************************/ gboolean nmc_print (const NmcConfig *nmc_config, |