diff options
Diffstat (limited to 'clients/cli')
| -rw-r--r-- | clients/cli/agent.c | 24 | ||||
| -rw-r--r-- | clients/cli/common.c | 108 | ||||
| -rw-r--r-- | clients/cli/common.h | 15 | ||||
| -rw-r--r-- | clients/cli/connections.c | 477 | ||||
| -rw-r--r-- | clients/cli/connections.h | 2 | ||||
| -rw-r--r-- | clients/cli/devices.c | 463 | ||||
| -rw-r--r-- | clients/cli/general.c | 49 | ||||
| -rw-r--r-- | clients/cli/meson.build | 8 | ||||
| -rw-r--r-- | clients/cli/nmcli.c | 49 | ||||
| -rw-r--r-- | clients/cli/nmcli.h | 6 | ||||
| -rw-r--r-- | clients/cli/polkit-agent.c | 16 | ||||
| -rw-r--r-- | clients/cli/settings.c | 17 | ||||
| -rw-r--r-- | clients/cli/settings.h | 3 | ||||
| -rw-r--r-- | clients/cli/utils.c | 65 | ||||
| -rw-r--r-- | clients/cli/utils.h | 6 |
15 files changed, 769 insertions, 539 deletions
diff --git a/clients/cli/agent.c b/clients/cli/agent.c index bbfe47fb..6c116153 100644 --- a/clients/cli/agent.c +++ b/clients/cli/agent.c @@ -25,7 +25,6 @@ #include <stdio.h> #include <stdlib.h> -#include <errno.h> #include <readline/readline.h> #include <readline/history.h> @@ -85,7 +84,8 @@ set_deftext (void) } static gboolean -get_secrets_from_user (const char *request_id, +get_secrets_from_user (const NmcConfig *nmc_config, + const char *request_id, const char *title, const char *msg, GPtrArray *secrets) @@ -104,7 +104,10 @@ 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->pretty_name, secret->entry_id); + if (secret->no_prompt_entry_id) + pwd = nmc_readline (nmc_config, "%s: ", secret->pretty_name); + else + pwd = nmc_readline (nmc_config, "%s (%s): ", secret->pretty_name, secret->entry_id); /* No password provided, cancel the secrets. */ if (!pwd) @@ -123,17 +126,16 @@ secrets_requested (NMSecretAgentSimple *agent, GPtrArray *secrets, gpointer user_data) { - NmCli *nmc = (NmCli *) user_data; - gboolean success = FALSE; + NmCli *nmc = user_data; + gboolean success; if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) nmc_terminal_erase_line (); - success = get_secrets_from_user (request_id, title, msg, secrets); - if (success) - nm_secret_agent_simple_response (agent, request_id, secrets); - else - nm_secret_agent_simple_response (agent, request_id, NULL); + success = get_secrets_from_user (&nmc->nmc_config, request_id, title, msg, secrets); + nm_secret_agent_simple_response (agent, + request_id, + success ? secrets : NULL); } static NMCResultCode @@ -149,7 +151,7 @@ do_agent_secret (NmCli *nmc, int argc, char **argv) /* We keep running */ nmc->should_wait++; - nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (nmc->secret_agent), NULL); + nm_secret_agent_simple_enable (nmc->secret_agent, NULL); g_signal_connect (nmc->secret_agent, NM_SECRET_AGENT_SIMPLE_REQUEST_SECRETS, G_CALLBACK (secrets_requested), diff --git a/clients/cli/common.c b/clients/cli/common.c index d3f5f865..3c1c315d 100644 --- a/clients/cli/common.c +++ b/clients/cli/common.c @@ -25,7 +25,6 @@ #include <stdio.h> #include <stdlib.h> -#include <errno.h> #include <sys/ioctl.h> #include <readline/readline.h> #include <readline/history.h> @@ -661,12 +660,12 @@ vpn_openconnect_get_secrets (NMConnection *connection, GPtrArray *secrets) } static gboolean -get_secrets_from_user (const char *request_id, +get_secrets_from_user (const NmcConfig *nmc_config, + const char *request_id, const char *title, const char *msg, NMConnection *connection, gboolean ask, - gboolean echo_on, GHashTable *pwds_hash, GPtrArray *secrets) { @@ -686,6 +685,8 @@ get_secrets_from_user (const char *request_id, pwd = g_strdup (pwd); } else { if (ask) { + gboolean echo_on; + if (secret->value) { if (!g_strcmp0 (secret->vpn_type, NM_DBUS_INTERFACE ".openconnect")) { /* Do not present and ask user for openconnect secrets, we already have them */ @@ -698,10 +699,16 @@ get_secrets_from_user (const char *request_id, } if (msg) g_print ("%s\n", msg); - pwd = nmc_readline_echo (secret->is_secret - ? echo_on - : TRUE, - "%s (%s): ", secret->pretty_name, secret->entry_id); + + echo_on = secret->is_secret + ? nmc_config->show_secrets + : TRUE; + + if (secret->no_prompt_entry_id) + pwd = nmc_readline_echo (nmc_config, echo_on, "%s: ", secret->pretty_name); + else + pwd = nmc_readline_echo (nmc_config, echo_on, "%s (%s): ", secret->pretty_name, secret->entry_id); + if (!pwd) pwd = g_strdup (""); } else { @@ -763,15 +770,21 @@ nmc_secrets_requested (NMSecretAgentSimple *agent, g_free (path); } - success = get_secrets_from_user (request_id, title, msg, connection, nmc->nmc_config.in_editor || nmc->ask, - nmc->nmc_config.show_secrets, nmc->pwds_hash, secrets); + success = get_secrets_from_user (&nmc->nmc_config, + request_id, + title, + msg, + connection, + nmc->nmc_config.in_editor || nmc->ask, + nmc->pwds_hash, + secrets); if (success) nm_secret_agent_simple_response (agent, request_id, secrets); else { /* Unregister our secret agent on failure, so that another agent * may be tried */ if (nmc->secret_agent) { - nm_secret_agent_old_unregister (nmc->secret_agent, NULL, NULL); + nm_secret_agent_old_unregister (NM_SECRET_AGENT_OLD (nmc->secret_agent), NULL, NULL); g_clear_object (&nmc->secret_agent); } } @@ -847,7 +860,8 @@ stdin_ready_cb (GIOChannel * io, GIOCondition condition, gpointer data) } static char * -nmc_readline_helper (const char *prompt) +nmc_readline_helper (const NmcConfig *nmc_config, + const char *prompt) { GIOChannel *io = NULL; guint io_watch_id; @@ -884,7 +898,7 @@ read_again: if (nmc_seen_sigint ()) { /* Ctrl-C */ nmc_clear_sigint (); - if ( nm_cli.nmc_config.in_editor + if ( nmc_config->in_editor || (rl_string && *rl_string)) { /* In editor, or the line is not empty */ /* Call readline again to get new prompt (repeat) */ @@ -926,22 +940,19 @@ read_again: * this function returns NULL. */ char * -nmc_readline (const char *prompt_fmt, ...) +nmc_readline (const NmcConfig *nmc_config, + const char *prompt_fmt, + ...) { va_list args; - char *prompt, *str; + gs_free char *prompt = NULL; rl_initialize (); va_start (args, prompt_fmt); prompt = g_strdup_vprintf (prompt_fmt, args); va_end (args); - - str = nmc_readline_helper (prompt); - - g_free (prompt); - - return str; + return nmc_readline_helper (nmc_config, prompt); } static void @@ -976,10 +987,14 @@ nmc_secret_redisplay (void) * nmc_readline(TRUE, ...) == nmc_readline(...) */ char * -nmc_readline_echo (gboolean echo_on, const char *prompt_fmt, ...) +nmc_readline_echo (const NmcConfig *nmc_config, + gboolean echo_on, + const char *prompt_fmt, + ...) { va_list args; - char *prompt, *str; + gs_free char *prompt = NULL; + char *str; HISTORY_STATE *saved_history; HISTORY_STATE passwd_history = { 0, }; @@ -996,9 +1011,7 @@ nmc_readline_echo (gboolean echo_on, const char *prompt_fmt, ...) rl_redisplay_function = nmc_secret_redisplay; } - str = nmc_readline_helper (prompt); - - g_free (prompt); + str = nmc_readline_helper (nmc_config, prompt); /* Restore the non-hiding behavior */ if (!echo_on) { @@ -1336,23 +1349,39 @@ nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char /** * nmc_complete_strings: * @prefix: a string to match - * @...: a %NULL-terminated list of candidate strings + * @nargs: the number of elements in @args. Or -1 if @args is a NULL terminated + * strv array. + * @args: the argument list. If @nargs is not -1, then some elements may + * be %NULL to indicate to silently skip the values. * * Prints all the matching candidates for completion. Useful when there's * no better way to suggest completion other than a hardcoded string list. */ void -nmc_complete_strings (const char *prefix, ...) +nmc_complete_strv (const char *prefix, gssize nargs, const char *const*args) { - va_list args; - const char *candidate; + gsize i, n; - va_start (args, prefix); - while ((candidate = va_arg (args, const char *))) { - if (!*prefix || matches (prefix, candidate)) - g_print ("%s\n", candidate); + if (prefix && !prefix[0]) + prefix = NULL; + + if (nargs < 0) { + nm_assert (nargs == -1); + n = NM_PTRARRAY_LEN (args); + } else + n = (gsize) nargs; + + for (i = 0; i < n; i++) { + const char *candidate = args[i]; + + if (!candidate) + continue; + if ( prefix + && !matches (prefix, candidate)) + continue; + + g_print ("%s\n", candidate); } - va_end (args); } /** @@ -1384,3 +1413,14 @@ nmc_error_get_simple_message (GError *error) else return error->message; } + +/*****************************************************************************/ + +NM_UTILS_LOOKUP_STR_DEFINE (nm_connectivity_to_string, NMConnectivityState, + NM_UTILS_LOOKUP_DEFAULT (N_("unknown")), + NM_UTILS_LOOKUP_ITEM (NM_CONNECTIVITY_NONE, N_("none")), + NM_UTILS_LOOKUP_ITEM (NM_CONNECTIVITY_PORTAL, N_("portal")), + NM_UTILS_LOOKUP_ITEM (NM_CONNECTIVITY_LIMITED, N_("limited")), + NM_UTILS_LOOKUP_ITEM (NM_CONNECTIVITY_FULL, N_("full")), + NM_UTILS_LOOKUP_ITEM_IGNORE (NM_CONNECTIVITY_UNKNOWN), +); diff --git a/clients/cli/common.h b/clients/cli/common.h index c180dfb7..688f2819 100644 --- a/clients/cli/common.h +++ b/clients/cli/common.h @@ -59,8 +59,13 @@ char *nmc_unique_connection_name (const GPtrArray *connections, const char *try_name); void nmc_cleanup_readline (void); -char *nmc_readline (const char *prompt_fmt, ...) G_GNUC_PRINTF (1, 2); -char *nmc_readline_echo (gboolean echo_on, const char *prompt_fmt, ...) G_GNUC_PRINTF (2, 3); +char *nmc_readline (const NmcConfig *nmc_config, + const char *prompt_fmt, + ...) G_GNUC_PRINTF (2, 3); +char *nmc_readline_echo (const NmcConfig *nmc_config, + gboolean echo_on, + const char *prompt_fmt, + ...) G_GNUC_PRINTF (3, 4); NmcCompEntryFunc nmc_rl_compentry_func_wrap (const char *const*values); char *nmc_rl_gen_func_basic (const char *text, int state, const char *const*words); char *nmc_rl_gen_func_ifnames (const char *text, int state); @@ -83,7 +88,9 @@ typedef struct { void nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char **argv); -void nmc_complete_strings (const char *prefix, ...) G_GNUC_NULL_TERMINATED; +void nmc_complete_strv (const char *prefix, gssize nargs, const char *const*args); + +#define nmc_complete_strings(prefix, ...) nmc_complete_strv ((prefix), NM_NARG (__VA_ARGS__), (const char *const[]) { __VA_ARGS__ }) void nmc_complete_bool (const char *prefix); @@ -93,4 +100,6 @@ extern const NmcMetaGenericInfo *const metagen_ip4_config[]; extern const NmcMetaGenericInfo *const metagen_ip6_config[]; extern const NmcMetaGenericInfo *const metagen_dhcp_config[]; +const char *nm_connectivity_to_string (NMConnectivityState connectivity); + #endif /* NMC_COMMON_H */ diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 8a10691e..6db44f87 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -22,14 +22,13 @@ #include "connections.h" #include <stdio.h> -#include <string.h> #include <stdlib.h> #include <unistd.h> -#include <errno.h> #include <signal.h> #include <netinet/ether.h> #include <readline/readline.h> #include <readline/history.h> +#include <fcntl.h> #include "nm-client-utils.h" #include "nm-vpn-helpers.h" @@ -140,15 +139,68 @@ active_connection_get_state_ord (NMActiveConnection *active) return -1; } -static int -active_connection_cmp (NMActiveConnection *ac_a, NMActiveConnection *ac_b) +int +nmc_active_connection_cmp (NMActiveConnection *ac_a, NMActiveConnection *ac_b) { + NMSettingIPConfig *s_ip; + NMRemoteConnection *conn; + NMIPConfig *da_ip; + NMIPConfig *db_ip; + int da_num_addrs; + int db_num_addrs; + int cmp = 0; + + /* Non-active sort last. */ NM_CMP_SELF (ac_a, ac_b); NM_CMP_DIRECT (active_connection_get_state_ord (ac_b), active_connection_get_state_ord (ac_a)); - NM_CMP_DIRECT_STRCMP0 (nm_active_connection_get_id (ac_a), nm_active_connection_get_id (ac_b)); - NM_CMP_DIRECT_STRCMP0 (nm_active_connection_get_connection_type (ac_a), nm_active_connection_get_connection_type (ac_b)); - NM_CMP_DIRECT_STRCMP0 (nm_object_get_path (NM_OBJECT (ac_a)), nm_object_get_path (NM_OBJECT (ac_b))); + + /* Shared connections (likely hotspots) go on the top if possible */ + conn = nm_active_connection_get_connection (ac_a); + s_ip = conn ? nm_connection_get_setting_ip6_config (NM_CONNECTION (conn)) : NULL; + if (s_ip && strcmp (nm_setting_ip_config_get_method (s_ip), NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) + cmp++; + conn = nm_active_connection_get_connection (ac_b); + s_ip = conn ? nm_connection_get_setting_ip6_config (NM_CONNECTION (conn)) : NULL; + if (s_ip && strcmp (nm_setting_ip_config_get_method (s_ip), NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) + cmp--; + NM_CMP_RETURN (cmp); + + conn = nm_active_connection_get_connection (ac_a); + s_ip = conn ? nm_connection_get_setting_ip4_config (NM_CONNECTION (conn)) : NULL; + if (s_ip && strcmp (nm_setting_ip_config_get_method (s_ip), NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) + cmp++; + conn = nm_active_connection_get_connection (ac_b); + s_ip = conn ? nm_connection_get_setting_ip4_config (NM_CONNECTION (conn)) : NULL; + if (s_ip && strcmp (nm_setting_ip_config_get_method (s_ip), NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) + cmp--; + NM_CMP_RETURN (cmp); + + /* VPNs go next */ + NM_CMP_DIRECT (!!nm_active_connection_get_vpn (ac_a), + !!nm_active_connection_get_vpn (ac_b)); + + /* Default devices are prioritized */ + NM_CMP_DIRECT (nm_active_connection_get_default (ac_a), + nm_active_connection_get_default (ac_b)); + + /* Default IPv6 devices are prioritized */ + NM_CMP_DIRECT (nm_active_connection_get_default6 (ac_a), + nm_active_connection_get_default6 (ac_b)); + + /* Sort by number of addresses. */ + da_ip = nm_active_connection_get_ip4_config (ac_a); + da_num_addrs = da_ip ? nm_ip_config_get_addresses (da_ip)->len : 0; + db_ip = nm_active_connection_get_ip4_config (ac_b); + db_num_addrs = db_ip ? nm_ip_config_get_addresses (db_ip)->len : 0; + + da_ip = nm_active_connection_get_ip6_config (ac_a); + da_num_addrs += da_ip ? nm_ip_config_get_addresses (da_ip)->len : 0; + db_ip = nm_active_connection_get_ip6_config (ac_b); + db_num_addrs += db_ip ? nm_ip_config_get_addresses (db_ip)->len : 0; + + NM_CMP_DIRECT (da_num_addrs, db_num_addrs); + return 0; } @@ -742,6 +794,7 @@ const NmcMetaGenericInfo *const metagen_con_active_vpn[_NMC_GENERIC_INFO_TYPE_CO NM_SETTING_IP4_CONFIG_SETTING_NAME","\ NM_SETTING_IP6_CONFIG_SETTING_NAME","\ NM_SETTING_SERIAL_SETTING_NAME","\ + NM_SETTING_WIFI_P2P_SETTING_NAME","\ NM_SETTING_PPP_SETTING_NAME","\ NM_SETTING_PPPOE_SETTING_NAME","\ NM_SETTING_ADSL_SETTING_NAME","\ @@ -769,6 +822,7 @@ const NmcMetaGenericInfo *const metagen_con_active_vpn[_NMC_GENERIC_INFO_TYPE_CO NM_SETTING_VXLAN_SETTING_NAME"," \ NM_SETTING_WPAN_SETTING_NAME","\ NM_SETTING_6LOWPAN_SETTING_NAME","\ + NM_SETTING_WIREGUARD_SETTING_NAME","\ NM_SETTING_PROXY_SETTING_NAME"," \ NM_SETTING_TC_CONFIG_SETTING_NAME"," \ NM_SETTING_SRIOV_SETTING_NAME"," \ @@ -991,8 +1045,10 @@ usage_connection_add (void) " [source-port-min <0-65535>]\n" " [source-port-max <0-65535>]\n" " [destination-port <0-65535>]\n\n" - " wpan: [short-addr <0x0000-0xffff>]\n\n" - " [pan-id <0x0000-0xffff>]\n\n" + " wpan: [short-addr <0x0000-0xffff>]\n" + " [pan-id <0x0000-0xffff>]\n" + " [page <default|0-31>]\n" + " [channel <default|0-26>]\n" " [mac <MAC address>]\n\n" " 6lowpan: dev <parent device (connection UUID, ifname, or MAC)>\n" " dummy:\n\n" @@ -1141,12 +1197,20 @@ construct_header_name (const char *base, const char *spec) } static int -get_ac_for_connection_cmp (gconstpointer pa, gconstpointer pb, gpointer user_data) +get_ac_for_connection_cmp (gconstpointer pa, gconstpointer pb) { NMActiveConnection *ac_a = *((NMActiveConnection *const*) pa); NMActiveConnection *ac_b = *((NMActiveConnection *const*) pb); - return active_connection_cmp (ac_a, ac_b); + NM_CMP_RETURN (nmc_active_connection_cmp (ac_a, ac_b)); + NM_CMP_DIRECT_STRCMP0 (nm_active_connection_get_id (ac_a), + nm_active_connection_get_id (ac_b)); + NM_CMP_DIRECT_STRCMP0 (nm_active_connection_get_connection_type (ac_a), + nm_active_connection_get_connection_type (ac_b)); + NM_CMP_DIRECT_STRCMP0 (nm_object_get_path (NM_OBJECT (ac_a)), + nm_object_get_path (NM_OBJECT (ac_b))); + + g_return_val_if_reached (0); } static NMActiveConnection * @@ -1172,7 +1236,7 @@ get_ac_for_connection (const GPtrArray *active_cons, NMConnection *connection, G } if (result) { - g_ptr_array_sort_with_data (result, get_ac_for_connection_cmp, NULL); + g_ptr_array_sort (result, get_ac_for_connection_cmp); best_candidate = result->pdata[0]; } @@ -1629,12 +1693,10 @@ con_show_get_items_cmp (gconstpointer pa, gconstpointer pb, gpointer user_data) switch (item) { case NMC_SORT_ACTIVE: - NM_CMP_DIRECT (active_connection_get_state_ord (ac_b), - active_connection_get_state_ord (ac_a)); + NM_CMP_RETURN (nmc_active_connection_cmp (ac_b, ac_a)); break; case NMC_SORT_ACTIVE_INV: - NM_CMP_DIRECT (active_connection_get_state_ord (ac_a), - active_connection_get_state_ord (ac_b)); + NM_CMP_RETURN (nmc_active_connection_cmp (ac_a, ac_b)); break; case NMC_SORT_TYPE: @@ -1673,13 +1735,12 @@ con_show_get_items_cmp (gconstpointer pa, gconstpointer pb, gpointer user_data) nm_connection_get_uuid (c_b)); NM_CMP_DIRECT_STRCMP0 (nm_connection_get_path (c_a), nm_connection_get_path (c_b)); - - /* This line is not expected to be reached, because there shouldn't be two - * different connections with the same path. Anyway, fall-through and compare by - * active connections... */ } - return active_connection_cmp (ac_a, ac_b); + NM_CMP_DIRECT_STRCMP0 (nm_object_get_path (NM_OBJECT (ac_a)), + nm_object_get_path (NM_OBJECT (ac_b))); + + g_return_val_if_reached (0); } static GPtrArray * @@ -1755,7 +1816,7 @@ con_show_get_items (NmCli *nmc, gboolean active_only, gboolean show_active_field * color (activated or not) based on primary_active. */ if (!row_data) { /* this is unexpected. The active connection references a connection that - * seemingly no longer exists. It's a bug in libnm. Add a row nontheless. */ + * seemingly no longer exists. It's a bug in libnm. Add a row nonetheless. */ row_data = _metagen_con_show_row_data_new_for_connection (c, show_active_fields); g_hash_table_insert (row_hash, c, row_data); } @@ -1985,8 +2046,7 @@ do_connections_show (NmCli *nmc, int argc, char **argv) } } - /* Optionally start paging the output. */ - nmc_terminal_spawn_pager (&nmc->nmc_config); + nm_cli_spawn_pager (nmc); items = con_show_get_items (nmc, active_only, show_active_fields, order); g_ptr_array_add (items, NULL); @@ -2287,7 +2347,7 @@ find_device_for_connection (NmCli *nmc, continue; if (!nm_device_connection_compatible (dev, connection, error)) { - g_prefix_error (error, _("device '%s' not compatible with connection '%s':"), + g_prefix_error (error, _("device '%s' not compatible with connection '%s': "), iface, nm_setting_connection_get_id (s_con)); return FALSE; } @@ -2340,6 +2400,43 @@ typedef struct { NMActiveConnection *active; } ActivateConnectionInfo; +static void +active_connection_hint (GString *return_text, + NMActiveConnection *active, + NMDevice *device) +{ + NMRemoteConnection *connection; + nm_auto_free_gstring GString *hint = NULL; + const GPtrArray *devices; + guint i; + + if (!active) + return; + + if (!nm_streq (NM_CONFIG_DEFAULT_LOGGING_BACKEND, "journal")) + return; + + connection = nm_active_connection_get_connection (active); + g_return_if_fail (connection); + + hint = g_string_new ("journalctl -xe "); + g_string_append_printf (hint, "NM_CONNECTION=%s", + nm_connection_get_uuid (NM_CONNECTION (connection))); + + if (device) + g_string_append_printf (hint, " + NM_DEVICE=%s", nm_device_get_iface (device)); + else { + devices = nm_active_connection_get_devices (active); + for (i = 0; i < devices->len; i++) { + g_string_append_printf (hint, " + NM_DEVICE=%s", + nm_device_get_iface (NM_DEVICE (g_ptr_array_index (devices, i)))); + } + } + + g_string_append (return_text, "\n"); + g_string_append_printf (return_text, _("Hint: use '%s' to get more details."), hint->str); +} + static void activate_connection_info_finish (ActivateConnectionInfo *info); static void @@ -2368,6 +2465,7 @@ check_activated (ActivateConnectionInfo *info) nm_assert (reason); g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s"), reason); + active_connection_hint (nmc->return_text, info->active, info->device); nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; activate_connection_info_finish (info); break; @@ -2375,7 +2473,7 @@ check_activated (ActivateConnectionInfo *info) if (nmc->secret_agent) { NMRemoteConnection *connection = nm_active_connection_get_connection (info->active); - nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (nmc->secret_agent), + nm_secret_agent_simple_enable (nmc->secret_agent, nm_connection_get_path (NM_CONNECTION (connection))); } break; @@ -2490,6 +2588,7 @@ activate_connection_cb (GObject *client, GAsyncResult *result, gpointer user_dat g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s"), error->message); g_error_free (error); + active_connection_hint (nmc->return_text, info->active, info->device); nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; activate_connection_info_finish (info); } else { @@ -2676,7 +2775,6 @@ nmc_activate_connection (NmCli *nmc, g_hash_table_destroy (nmc->pwds_hash); nmc->pwds_hash = pwds_hash; - /* Create secret agent */ nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-connect"); if (nmc->secret_agent) { g_signal_connect (nmc->secret_agent, @@ -2726,14 +2824,14 @@ do_connection_up (NmCli *nmc, int argc, char **argv) argc_ptr = &argc; if (argc == 0 && nmc->ask) { - char *line; + gs_free char *line = NULL; /* nmc_do_cmd() should not call this with argc=0. */ g_assert (!nmc->complete); - line = nmc_readline (PROMPT_CONNECTION); + line = nmc_readline (&nmc->nmc_config, + PROMPT_CONNECTION); nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num); - g_free (line); argv_ptr = &arg_arr; argc_ptr = &arg_num; } @@ -2906,6 +3004,7 @@ connection_cb_info_finish (ConnectionCbInfo *info, gpointer obj) nm_clear_g_source (&info->timeout_id); nm_clear_g_cancellable (&info->cancellable); + g_ptr_array_free (info->obj_list, TRUE); g_signal_handlers_disconnect_by_func (info->nmc->client, connection_removed_cb, info); @@ -2980,9 +3079,11 @@ do_connection_down (NmCli *nmc, int argc, char **argv) g_assert (!nmc->complete); if (nmc->ask) { - char *line = nmc_readline (PROMPT_ACTIVE_CONNECTIONS); + gs_free char *line = NULL; + + line = nmc_readline (&nmc->nmc_config, + PROMPT_ACTIVE_CONNECTIONS); nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num); - g_free (line); arg_ptr = arg_arr; } if (arg_num == 0) { @@ -3204,7 +3305,7 @@ get_valid_properties_string (const NMMetaSettingValidPartItem *const*array, str = g_string_sized_new (1024); for (i = 0; i < 2; i++, iter = array_slv) { - for(; !full_match && iter && *iter; iter++) { + for (; !full_match && iter && *iter; iter++) { const NMMetaSettingInfoEditor *setting_info = (*iter)->setting_info; if ( !(g_str_has_prefix (setting_info->general->setting_name, prefix)) @@ -3850,9 +3951,13 @@ reset_options (void) } static gboolean -set_property (NMConnection *connection, - const char *setting_name, const char *property, const char *value, - char modifier, GError **error) +set_property (NMClient *client, + NMConnection *connection, + const char *setting_name, + const char *property, + const char *value, + char modifier, + GError **error) { gs_free char *property_name = NULL, *value_free = NULL; NMSetting *setting; @@ -3885,7 +3990,7 @@ set_property (NMConnection *connection, value = value_free = g_strdup (value); nmc_setting_reset_property (setting, property_name, NULL); } - if (!nmc_setting_set_property (setting, property_name, value, &local)) { + if (!nmc_setting_set_property (client, setting, property_name, value, &local)) { g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, _("Error: failed to modify %s.%s: %s."), setting_name, property, local->message); @@ -3937,7 +4042,7 @@ set_option (NmCli *nmc, NMConnection *connection, const NMMetaAbstractInfo *abst if (option && option->check_and_set) { return option->check_and_set (nmc, connection, option, value, error); } else if (value) { - return set_property (connection, setting_name, property_name, + return set_property (nmc->client, connection, setting_name, property_name, value, inf_flags & NM_META_PROPERTY_INF_FLAG_MULTI ? '+' : '\0', error); } else if (inf_flags & NM_META_PROPERTY_INF_FLAG_REQD) { g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, @@ -3985,7 +4090,7 @@ con_settings (NMConnection *connection, const NMMetaSettingValidPartItem *const* /* * Make sure all required settings are in place (should be called when - * it's possible that a type is aready set). + * it's possible that a type is already set). */ static void ensure_settings (NMConnection *connection, const NMMetaSettingValidPartItem *const*item) @@ -4059,7 +4164,7 @@ set_connection_type (NmCli *nmc, NMConnection *con, const OptionInfo *option, co } if (slave_type) { - if (!set_property (con, NM_SETTING_CONNECTION_SETTING_NAME, + if (!set_property (nmc->client, con, NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type, '\0', error)) { return FALSE; @@ -4076,7 +4181,7 @@ set_connection_type (NmCli *nmc, NMConnection *con, const OptionInfo *option, co NM_SETTING_CONNECTION_INTERFACE_NAME); } - if (!set_property (con, option->setting_info->general->setting_name, option->property, value, '\0', error)) + if (!set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '\0', error)) return FALSE; if (!con_settings (con, &type_settings, &slv_settings, error)) @@ -4105,7 +4210,7 @@ set_connection_iface (NmCli *nmc, NMConnection *con, const OptionInfo *option, c } } - return set_property (con, option->setting_info->general->setting_name, option->property, value, '\0', error); + return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '\0', error); } static gboolean @@ -4128,13 +4233,13 @@ set_connection_master (NmCli *nmc, NMConnection *con, const OptionInfo *option, connections = nm_client_get_connections (nmc->client); value = normalized_master_for_slave (connections, value, slave_type, &slave_type); - if (!set_property (con, NM_SETTING_CONNECTION_SETTING_NAME, + if (!set_property (nmc->client, con, NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type, '\0', error)) { return FALSE; } - return set_property (con, option->setting_info->general->setting_name, option->property, value, '\0', error); + return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '\0', error); } static gboolean @@ -4248,7 +4353,7 @@ set_bluetooth_type (NmCli *nmc, NMConnection *con, const OptionInfo *option, con return FALSE; } - return set_property (con, option->setting_info->general->setting_name, option->property, value, '\0', error); + return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '\0', error); } static gboolean @@ -4267,7 +4372,7 @@ set_ip4_address (NmCli *nmc, NMConnection *con, const OptionInfo *option, const NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NULL); } - return set_property (con, option->setting_info->general->setting_name, option->property, value, + return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '+', error); } @@ -4287,7 +4392,7 @@ set_ip6_address (NmCli *nmc, NMConnection *con, const OptionInfo *option, const NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL, NULL); } - return set_property (con, option->setting_info->general->setting_name, option->property, value, + return set_property (nmc->client, con, option->setting_info->general->setting_name, option->property, value, '+', error); } @@ -4573,7 +4678,7 @@ nmc_read_connection_properties (NmCli *nmc, if (!*argc && nmc->complete) complete_property (setting, strv[1], value ?: "", connection); - if (!set_property (connection, setting_name, strv[1], value, modifier, error)) + if (!set_property (nmc->client, connection, setting_name, strv[1], value, modifier, error)) return FALSE; } else { NMMetaSettingType s; @@ -4853,7 +4958,9 @@ ask_option (NmCli *nmc, NMConnection *connection, const NMMetaAbstractInfo *abst g_print (_("You can specify this option more than once. Press <Enter> when you're done.\n")); again: - value = nmc_readline ("%s", prompt); + value = nmc_readline (&nmc->nmc_config, + "%s", + prompt); if (multi && !value) return; @@ -4943,23 +5050,25 @@ questionnaire_mandatory (NmCli *nmc, NMConnection *connection) } static gboolean -want_provide_opt_args (const char *type, int num) +want_provide_opt_args (const NmcConfig *nmc_config, + const char *type, + guint num) { - char *answer; - gboolean ret = TRUE; + gs_free char *answer = NULL; /* Ask for optional arguments. */ g_print (ngettext ("There is %d optional setting for %s.\n", - "There are %d optional settings for %s.\n", num), - num, type); - answer = nmc_readline (ngettext ("Do you want to provide it? %s", - "Do you want to provide them? %s", num), + "There are %d optional settings for %s.\n", + num), + (int) num, + type); + answer = nmc_readline (nmc_config, + ngettext ("Do you want to provide it? %s", + "Do you want to provide them? %s", + num), prompt_yes_no (TRUE, NULL)); - answer = answer ? g_strstrip (answer) : NULL; - if (answer && !matches (answer, WORD_YES)) - ret = FALSE; - g_free (answer); - return ret; + nm_strstrip (answer); + return !answer || matches (answer, WORD_YES); } static gboolean @@ -5029,7 +5138,9 @@ again: /* Now ask for the settings. */ if ( already_confirmed - || want_provide_opt_args (_(setting_info->pretty_name), infos->len)) { + || want_provide_opt_args (&nmc->nmc_config, + _(setting_info->pretty_name), + infos->len)) { ask_option (nmc, connection, infos->pdata[0]); already_confirmed = TRUE; /* asking for an option may enable other options. Create the list again. */ @@ -5059,7 +5170,7 @@ do_connection_add (NmCli *nmc, int argc, char **argv) next_arg (nmc, &argc, &argv, NULL); - rl_attempted_completion_function = (rl_completion_func_t *) nmcli_con_add_tab_completion; + rl_attempted_completion_function = nmcli_con_add_tab_completion; nmc->return_value = NMC_RESULT_SUCCESS; @@ -6615,7 +6726,7 @@ progress_activation_editor_cb (gpointer user_data) NMRemoteConnection *connection; connection = nm_active_connection_get_connection (ac); - nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (info->nmc->secret_agent), + nm_secret_agent_simple_enable (info->nmc->secret_agent, nm_object_get_path (NM_OBJECT (connection))); } @@ -6656,6 +6767,10 @@ activate_connection_editor_cb (GObject *client, } else g_object_unref (active); } + + nm_g_object_unref (info->device); + g_free (info); + set_info_and_signal_editor_thread (error, monitor_ac_info); g_clear_error (&error); } @@ -6749,20 +6864,16 @@ is_connection_dirty (NMConnection *connection, NMRemoteConnection *remote) } static gboolean -confirm_quit (void) +confirm_quit (const NmcConfig *nmc_config) { - char *answer; - gboolean want_quit = FALSE; + gs_free char *answer = NULL; - answer = nmc_readline (_("The connection is not saved. " + answer = nmc_readline (nmc_config, + _("The connection is not saved. " "Do you really want to quit? %s"), prompt_yes_no (FALSE, NULL)); - answer = answer ? g_strstrip (answer) : NULL; - if (answer && matches (answer, WORD_YES)) - want_quit = TRUE; - - g_free (answer); - return want_quit; + nm_strstrip (answer); + return (answer && matches (answer, WORD_YES)); } /* @@ -6797,7 +6908,7 @@ property_edit_submenu (NmCli *nmc, gboolean removed; gboolean dirty; - /* Get the remote connection again, it may have disapeared */ + /* Get the remote connection again, it may have disappeared */ removed = refresh_remote_connection (rem_con_weak, rem_con); if (removed) { g_print (_("The connection profile has been removed from another client. " @@ -6810,10 +6921,13 @@ property_edit_submenu (NmCli *nmc, if (nmc->editor_status_line) editor_show_status_line (connection, dirty, temp_changes); - cmd_property_user = nmc_readline ("%s", prompt); + cmd_property_user = nmc_readline (&nmc->nmc_config, + "%s", + prompt); if (!cmd_property_user || !*cmd_property_user) continue; - cmdsub = parse_editor_sub_cmd (g_strstrip (cmd_property_user), &cmd_property_arg); + g_strstrip (cmd_property_user); + cmdsub = parse_editor_sub_cmd (cmd_property_user, &cmd_property_arg); switch (cmdsub) { case NMC_EDITOR_SUB_CMD_SET: @@ -6834,7 +6948,9 @@ property_edit_submenu (NmCli *nmc, g_print (_("Allowed values for '%s' property: %s\n"), prop_name, avals_str); } - prop_val_user = nmc_readline (_("Enter '%s' value: "), prop_name); + prop_val_user = nmc_readline (&nmc->nmc_config, + _("Enter '%s' value: "), + prop_name); } else prop_val_user = g_strdup (cmd_property_arg); @@ -6846,7 +6962,7 @@ property_edit_submenu (NmCli *nmc, nmc_property_set_default_value (curr_setting, prop_name); } - set_result = nmc_setting_set_property (curr_setting, prop_name, prop_val_user, &tmp_err); + set_result = nmc_setting_set_property (nmc->client, curr_setting, prop_name, prop_val_user, &tmp_err); if (!set_result) { g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message); g_clear_error (&tmp_err); @@ -6862,12 +6978,14 @@ property_edit_submenu (NmCli *nmc, case NMC_EDITOR_SUB_CMD_CHANGE: rl_startup_hook = nmc_rl_set_deftext; nmc_rl_pre_input_deftext = nmc_setting_get_property_parsable (curr_setting, prop_name, NULL); - prop_val_user = nmc_readline (_("Edit '%s' value: "), prop_name); + prop_val_user = nmc_readline (&nmc->nmc_config, + _("Edit '%s' value: "), + prop_name); nmc_property_get_gvalue (curr_setting, prop_name, &prop_g_value); nmc_property_set_default_value (curr_setting, prop_name); - if (!nmc_setting_set_property (curr_setting, prop_name, prop_val_user, &tmp_err)) { + if (!nmc_setting_set_property (nmc->client, curr_setting, prop_name, prop_val_user, &tmp_err)) { g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message); g_clear_error (&tmp_err); g_signal_handlers_block_matched (curr_setting, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NULL); @@ -6879,19 +6997,20 @@ property_edit_submenu (NmCli *nmc, case NMC_EDITOR_SUB_CMD_REMOVE: if (cmd_property_arg) { unsigned long val_int = G_MAXUINT32; - char *option = NULL; + gs_free char *option = NULL; - if (!nmc_string_to_uint (cmd_property_arg, TRUE, 0, G_MAXUINT32, &val_int)) + if (!nmc_string_to_uint (cmd_property_arg, TRUE, 0, G_MAXUINT32, &val_int)) { option = g_strdup (cmd_property_arg); + g_strstrip (option); + } if (!nmc_setting_remove_property_option (curr_setting, prop_name, - option ? g_strstrip (option) : NULL, + option, (guint32) val_int, &tmp_err)) { g_print (_("Error: %s\n"), tmp_err->message); g_clear_error (&tmp_err); } - g_free (option); } else { if (!nmc_setting_reset_property (curr_setting, prop_name, &tmp_err)) { g_print (_("Error: failed to remove value of '%s': %s\n"), prop_name, @@ -6934,7 +7053,7 @@ property_edit_submenu (NmCli *nmc, case NMC_EDITOR_SUB_CMD_QUIT: if (is_connection_dirty (connection, *rem_con)) { - if (confirm_quit ()) + if (confirm_quit (&nmc->nmc_config)) return FALSE; } else return FALSE; @@ -6995,7 +7114,8 @@ create_setting_by_name (const char *name, const NMMetaSettingValidPartItem *cons } static const char * -ask_check_setting (const char *arg, +ask_check_setting (const NmcConfig *nmc_config, + const char *arg, const NMMetaSettingValidPartItem *const*valid_settings_main, const NMMetaSettingValidPartItem *const*valid_settings_slave, const char *valid_settings_str) @@ -7006,12 +7126,12 @@ ask_check_setting (const char *arg, if (!arg) { g_print (_("Available settings: %s\n"), valid_settings_str); - setting_name_user = nmc_readline (EDITOR_PROMPT_SETTING); + setting_name_user = nmc_readline (nmc_config, + EDITOR_PROMPT_SETTING); } else setting_name_user = g_strdup (arg); - if (setting_name_user) - g_strstrip (setting_name_user); + nm_strstrip (setting_name_user); if (!(setting_name = check_valid_name (setting_name_user, valid_settings_main, @@ -7025,7 +7145,8 @@ ask_check_setting (const char *arg, } static const char * -ask_check_property (const char *arg, +ask_check_property (const NmcConfig *nmc_config, + const char *arg, const char **valid_props, const char *valid_props_str) { @@ -7035,9 +7156,9 @@ ask_check_property (const char *arg, if (!arg) { g_print (_("Available properties: %s\n"), valid_props_str); - prop_name_user = nmc_readline (EDITOR_PROMPT_PROPERTY); - if (prop_name_user) - g_strstrip (prop_name_user); + prop_name_user = nmc_readline (nmc_config, + EDITOR_PROMPT_PROPERTY); + nm_strstrip (prop_name_user); } else prop_name_user = g_strdup (arg); @@ -7064,7 +7185,9 @@ update_connection_timestamp (NMConnection *src, NMConnection *dst) } static gboolean -confirm_connection_saving (NMConnection *local, NMConnection *remote) +confirm_connection_saving (const NmcConfig *nmc_config, + NMConnection *local, + NMConnection *remote) { NMSettingConnection *s_con_loc, *s_con_rem; gboolean ac_local, ac_remote; @@ -7082,16 +7205,15 @@ confirm_connection_saving (NMConnection *local, NMConnection *remote) ac_remote = FALSE; if (ac_local && !ac_remote) { - char *answer; - answer = nmc_readline (_("Saving the connection with 'autoconnect=yes'. " + gs_free char *answer = NULL; + + answer = nmc_readline (nmc_config, + _("Saving the connection with 'autoconnect=yes'. " "That might result in an immediate activation of the connection.\n" - "Do you still want to save? %s"), prompt_yes_no (TRUE, NULL)); - answer = answer ? g_strstrip (answer) : NULL; - if (!answer || matches (answer, WORD_YES)) - confirmed = TRUE; - else - confirmed = FALSE; - g_free (answer); + "Do you still want to save? %s"), + prompt_yes_no (TRUE, NULL)); + nm_strstrip (answer); + confirmed = (!answer || matches (answer, WORD_YES)); } return confirmed; } @@ -7196,9 +7318,11 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t if (nmc->editor_status_line) editor_show_status_line (connection, dirty, temp_changes); - cmd_user = nmc_readline ("%s", menu_ctx.main_prompt); + cmd_user = nmc_readline (&nmc->nmc_config, + "%s", + menu_ctx.main_prompt); - /* Get the remote connection again, it may have disapeared */ + /* Get the remote connection again, it may have disappeared */ removed = refresh_remote_connection (&weak, &rem_con); if (removed) { g_print (_("The connection profile has been removed from another client. " @@ -7208,7 +7332,9 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t if (!cmd_user || !*cmd_user) continue; - cmd = parse_editor_main_cmd (g_strstrip (cmd_user), &cmd_arg); + g_strstrip (cmd_user); + + cmd = parse_editor_main_cmd (cmd_user, &cmd_arg); split_editor_main_cmd_args (cmd_arg, &cmd_arg_s, &cmd_arg_p, &cmd_arg_v); switch (cmd) { @@ -7222,7 +7348,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t const char *const*avals; GError *tmp_err = NULL; - prop_name = ask_check_property (cmd_arg, + prop_name = ask_check_property (&nmc->nmc_config, + cmd_arg, (const char **) menu_ctx.valid_props, menu_ctx.valid_props_str); if (!prop_name) @@ -7236,10 +7363,12 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t g_print (_("Allowed values for '%s' property: %s\n"), prop_name, avals_str); } - prop_val_user = nmc_readline (_("Enter '%s' value: "), prop_name); + prop_val_user = nmc_readline (&nmc->nmc_config, + _("Enter '%s' value: "), + prop_name); /* Set property value */ - if (!nmc_setting_set_property (menu_ctx.curr_setting, prop_name, prop_val_user, &tmp_err)) { + if (!nmc_setting_set_property (nmc->client, menu_ctx.curr_setting, prop_name, prop_val_user, &tmp_err)) { g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message); g_clear_error (&tmp_err); } @@ -7294,11 +7423,13 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t g_print (_("Allowed values for '%s' property: %s\n"), prop_name, avals_str); } - cmd_arg_v = nmc_readline (_("Enter '%s' value: "), prop_name); + cmd_arg_v = nmc_readline (&nmc->nmc_config, + _("Enter '%s' value: "), + prop_name); } /* Set property value */ - if (!nmc_setting_set_property (ss, prop_name, cmd_arg_v, &tmp_err)) { + if (!nmc_setting_set_property (nmc->client, ss, prop_name, cmd_arg_v, &tmp_err)) { g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message); g_clear_error (&tmp_err); @@ -7317,7 +7448,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t NMSetting *setting; const char *user_arg = cmd_arg_s ?: cmd_arg_p; - setting_name = ask_check_setting (user_arg, + setting_name = ask_check_setting (&nmc->nmc_config, + user_arg, valid_settings_main, valid_settings_slave, valid_settings_str); @@ -7363,7 +7495,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t /* level 1 - setting selected */ const char *prop_name; - prop_name = ask_check_property (cmd_arg_p, + prop_name = ask_check_property (&nmc->nmc_config, + cmd_arg_p, (const char **) menu_ctx.valid_props, menu_ctx.valid_props_str); if (!prop_name) @@ -7386,7 +7519,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t GError *tmp_err = NULL; const char *prop_name; - prop_name = ask_check_property (cmd_arg, + prop_name = ask_check_property (&nmc->nmc_config, + cmd_arg, (const char **) menu_ctx.valid_props, menu_ctx.valid_props_str); if (!prop_name) @@ -7480,7 +7614,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t if (menu_ctx.level == 1) { const char *prop_name; - prop_name = ask_check_property (cmd_arg, + prop_name = ask_check_property (&nmc->nmc_config, + cmd_arg, (const char **) menu_ctx.valid_props, menu_ctx.valid_props_str); if (!prop_name) @@ -7682,9 +7817,12 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t } /* Ask for save confirmation if the connection changes to autoconnect=yes */ - if (nmc->editor_save_confirmation) - if (!confirm_connection_saving (connection, NM_CONNECTION (rem_con))) + if (nmc->editor_save_confirmation) { + if (!confirm_connection_saving (&nmc->nmc_config, + connection, + NM_CONNECTION (rem_con))) break; + } if (!rem_con) { /* Tell the settings service to add the new connection */ @@ -7823,7 +7961,8 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t nmc_editor_error->message); g_error_free (nmc_editor_error); } else { - nmc_readline (_("Monitoring connection activation (press any key to continue)\n")); + nmc_readline (&nmc->nmc_config, + _("Monitoring connection activation (press any key to continue)\n")); } if (nmc_editor_monitor_ac) { @@ -7897,7 +8036,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t case NMC_EDITOR_MAIN_CMD_QUIT: if (is_connection_dirty (connection, rem_con)) { - if (confirm_quit ()) + if (confirm_quit (&nmc->nmc_config)) cmd_loop = FALSE; /* quit command loop */ } else cmd_loop = FALSE; /* quit command loop */ @@ -8085,7 +8224,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) /* Setup some readline completion stuff */ /* Set a pointer to an alternative function to create matches */ - rl_attempted_completion_function = (rl_completion_func_t *) nmcli_editor_tab_completion; + rl_attempted_completion_function = nmcli_editor_tab_completion; /* Use ' ' and '.' as word break characters */ rl_completer_word_break_characters = ". "; @@ -8173,8 +8312,9 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) g_print (_("Error: invalid connection type; %s\n"), err1->message); g_clear_error (&err1); - type_ask = nmc_readline (EDITOR_PROMPT_CON_TYPE); - type = type_ask = type_ask ? g_strstrip (type_ask) : NULL; + type_ask = nmc_readline (&nmc->nmc_config, + EDITOR_PROMPT_CON_TYPE); + type = type_ask = nm_strstrip (type_ask); connection_type = check_valid_name_toplevel (type_ask, &slave_type, &err1); } nm_clear_g_free (&tmp_str); @@ -8367,14 +8507,14 @@ do_connection_clone (NmCli *nmc, int argc, char **argv) argc_ptr = &argc; if (argc == 0 && nmc->ask) { - char *line; + gs_free char *line = NULL; /* nmc_do_cmd() should not call this with argc=0. */ g_assert (!nmc->complete); - line = nmc_readline (PROMPT_CONNECTION); + line = nmc_readline (&nmc->nmc_config, + PROMPT_CONNECTION); nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num); - g_free (line); argv_ptr = &arg_arr; argc_ptr = &arg_num; } @@ -8390,9 +8530,10 @@ do_connection_clone (NmCli *nmc, int argc, char **argv) if (argv[0]) new_name = *argv; - else if (nmc->ask) - new_name = new_name_ask = nmc_readline (_("New connection name: ")); - else { + else if (nmc->ask) { + new_name = new_name_ask = nmc_readline (&nmc->nmc_config, + _("New connection name: ")); + } else { g_string_printf (nmc->return_text, _("Error: <new name> argument is missing.")); NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } @@ -8477,14 +8618,14 @@ do_connection_delete (NmCli *nmc, int argc, char **argv) if (argc == 0) { if (nmc->ask) { - char *line; + gs_free char *line = NULL; /* nmc_do_cmd() should not call this with argc=0. */ g_assert (!nmc->complete); - line = nmc_readline (PROMPT_CONNECTIONS); + line = nmc_readline (&nmc->nmc_config, + PROMPT_CONNECTIONS); nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num); - g_free (line); arg_ptr = arg_arr; } if (arg_num == 0) { @@ -8733,10 +8874,13 @@ do_connection_import (NmCli *nmc, int argc, char **argv) g_assert (!nmc->complete); if (nmc->ask) { - type_ask = nmc_readline ("%s: ", gettext (NM_META_TEXT_PROMPT_VPN_TYPE)); - filename_ask = nmc_readline (gettext (PROMPT_IMPORT_FILE)); - type = type_ask = type_ask ? g_strstrip (type_ask) : NULL; - filename = filename_ask = filename_ask ? g_strstrip (filename_ask) : NULL; + type_ask = nmc_readline (&nmc->nmc_config, + "%s: ", + gettext (NM_META_TEXT_PROMPT_VPN_TYPE)); + type = nm_strstrip (type_ask); + filename_ask = nmc_readline (&nmc->nmc_config, + gettext (PROMPT_IMPORT_FILE)); + filename = nm_strstrip (filename_ask); } else { g_string_printf (nmc->return_text, _("Error: No arguments provided.")); NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); @@ -8744,8 +8888,11 @@ do_connection_import (NmCli *nmc, int argc, char **argv) } while (argc > 0) { - if (argc == 1 && nmc->complete) - nmc_complete_strings (*argv, "type", "file", NULL); + if (argc == 1 && nmc->complete) { + nmc_complete_strings (*argv, + type ? NULL : "type", + filename ? NULL : "file"); + } if (strcmp (*argv, "type") == 0) { argc--; @@ -8755,8 +8902,13 @@ do_connection_import (NmCli *nmc, int argc, char **argv) NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT); } - if (argc == 1 && nmc->complete) - complete_option ((const NMMetaAbstractInfo *) nm_meta_property_info_vpn_service_type, *argv, NULL); + if ( argc == 1 + && nmc->complete) { + nmc_complete_strings (*argv, "wireguard"); + complete_option ((const NMMetaAbstractInfo *) nm_meta_property_info_vpn_service_type, + *argv, + NULL); + } if (!type) type = *argv; @@ -8796,21 +8948,26 @@ do_connection_import (NmCli *nmc, int argc, char **argv) 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 (nmc, NMC_RESULT_ERROR_UNKNOWN); - } + if (nm_streq (type, "wireguard")) + connection = nm_vpn_wireguard_import (filename, &error); + else { + 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 (nmc, NMC_RESULT_ERROR_UNKNOWN); + } - /* Import VPN configuration */ - plugin = nm_vpn_get_editor_plugin (service_type, &error); - if (!plugin) { - g_string_printf (nmc->return_text, _("Error: failed to load VPN plugin: %s."), - error->message); - NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN); + /* Import VPN configuration */ + plugin = nm_vpn_get_editor_plugin (service_type, &error); + if (!plugin) { + g_string_printf (nmc->return_text, _("Error: failed to load VPN plugin: %s."), + error->message); + NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN); + } + + connection = nm_vpn_editor_plugin_import (plugin, filename, &error); } - 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); @@ -8853,14 +9010,14 @@ do_connection_export (NmCli *nmc, int argc, char **argv) argc_ptr = &argc; if (argc == 0 && nmc->ask) { - char *line; + gs_free char *line = NULL; /* nmc_do_cmd() should not call this with argc=0. */ g_assert (!nmc->complete); - line = nmc_readline (PROMPT_VPN_CONNECTION); + line = nmc_readline (&nmc->nmc_config, + PROMPT_VPN_CONNECTION); nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num); - g_free (line); argv_ptr = &arg_arr; argc_ptr = &arg_num; } @@ -8883,8 +9040,10 @@ do_connection_export (NmCli *nmc, int argc, char **argv) goto finish; } - if (out_name == NULL && nmc->ask) - out_name = out_name_ask = nmc_readline (_("Output file name: ")); + if (!out_name && nmc->ask) { + out_name = out_name_ask = nmc_readline (&nmc->nmc_config, + _("Output file name: ")); + } type = nm_connection_get_connection_type (connection); if (g_strcmp0 (type, NM_SETTING_VPN_SETTING_NAME) != 0) { @@ -8908,7 +9067,7 @@ do_connection_export (NmCli *nmc, int argc, char **argv) else { nm_auto_close int fd = -1; - fd = g_mkstemp (tmpfile); + fd = g_mkstemp_full (tmpfile, O_RDWR | O_CLOEXEC, 0600); if (fd == -1) { g_string_printf (nmc->return_text, _("Error: failed to create temporary file %s."), tmpfile); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; @@ -9060,7 +9219,7 @@ do_connections (NmCli *nmc, int argc, char **argv) nmc_start_polkit_agent_start_try (nmc); /* Set completion function for 'nmcli con' */ - rl_attempted_completion_function = (rl_completion_func_t *) nmcli_con_tab_completion; + rl_attempted_completion_function = nmcli_con_tab_completion; nmc_do_cmd (nmc, connection_cmds, *argv, argc, argv); diff --git a/clients/cli/connections.h b/clients/cli/connections.h index 22bfa8ec..122a7e27 100644 --- a/clients/cli/connections.h +++ b/clients/cli/connections.h @@ -35,6 +35,8 @@ nmc_read_connection_properties (NmCli *nmc, NMMetaColor nmc_active_connection_state_to_color (NMActiveConnectionState state); +int nmc_active_connection_cmp (NMActiveConnection *ac_a, NMActiveConnection *ac_b); + extern const NmcMetaGenericInfo *const metagen_con_show[]; extern const NmcMetaGenericInfo *const metagen_con_active_general[]; extern const NmcMetaGenericInfo *const metagen_con_active_vpn[]; diff --git a/clients/cli/devices.c b/clients/cli/devices.c index 5aaf4ef8..04a8c988 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -22,9 +22,7 @@ #include "devices.h" #include <stdio.h> -#include <string.h> #include <stdlib.h> -#include <errno.h> #include <readline/readline.h> #include "nm-secret-agent-simple.h" @@ -44,43 +42,39 @@ static char * ap_wpa_rsn_flags_to_string (NM80211ApSecurityFlags flags) { - char *flags_str[16]; /* Enough space for flags and terminating NULL */ - char *ret_str; + char *flags_str[13]; int i = 0; if (flags & NM_802_11_AP_SEC_PAIR_WEP40) - flags_str[i++] = g_strdup ("pair_wpe40"); + flags_str[i++] = "pair_wpe40"; if (flags & NM_802_11_AP_SEC_PAIR_WEP104) - flags_str[i++] = g_strdup ("pair_wpe104"); + flags_str[i++] = "pair_wpe104"; if (flags & NM_802_11_AP_SEC_PAIR_TKIP) - flags_str[i++] = g_strdup ("pair_tkip"); + flags_str[i++] = "pair_tkip"; if (flags & NM_802_11_AP_SEC_PAIR_CCMP) - flags_str[i++] = g_strdup ("pair_ccmp"); + flags_str[i++] = "pair_ccmp"; if (flags & NM_802_11_AP_SEC_GROUP_WEP40) - flags_str[i++] = g_strdup ("group_wpe40"); + flags_str[i++] = "group_wpe40"; if (flags & NM_802_11_AP_SEC_GROUP_WEP104) - flags_str[i++] = g_strdup ("group_wpe104"); + flags_str[i++] = "group_wpe104"; if (flags & NM_802_11_AP_SEC_GROUP_TKIP) - flags_str[i++] = g_strdup ("group_tkip"); + flags_str[i++] = "group_tkip"; if (flags & NM_802_11_AP_SEC_GROUP_CCMP) - flags_str[i++] = g_strdup ("group_ccmp"); + flags_str[i++] = "group_ccmp"; if (flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - flags_str[i++] = g_strdup ("psk"); + flags_str[i++] = "psk"; if (flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) - flags_str[i++] = g_strdup ("802.1X"); + flags_str[i++] = "802.1X"; + if (flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) + flags_str[i++] = "sae"; + /* Make sure you grow flags_str when adding items here. */ if (i == 0) - flags_str[i++] = g_strdup (_("(none)")); + flags_str[i++] = _("(none)"); flags_str[i] = NULL; - ret_str = g_strjoinv (" ", flags_str); - - i = 0; - while (flags_str[i]) - g_free (flags_str[i++]); - - return ret_str; + return g_strjoinv (" ", flags_str); } static NMMetaColor @@ -116,6 +110,12 @@ _metagen_device_status_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_STATE: return nmc_meta_generic_get_str_i18n (nmc_device_state_to_string (nm_device_get_state (d)), get_type); + case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_IP4_CONNECTIVITY: + return nmc_meta_generic_get_str_i18n (nm_connectivity_to_string (nm_device_get_connectivity (d, AF_INET)), + get_type); + case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_IP6_CONNECTIVITY: + return nmc_meta_generic_get_str_i18n (nm_connectivity_to_string (nm_device_get_connectivity (d, AF_INET6)), + get_type); case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_DBUS_PATH: return nm_object_get_path (NM_OBJECT (d)); case NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CONNECTION: @@ -137,13 +137,15 @@ _metagen_device_status_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) const NmcMetaGenericInfo *const metagen_device_status[_NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_NUM + 1] = { #define _METAGEN_DEVICE_STATUS(type, name) \ [type] = NMC_META_GENERIC(name, .info_type = type, .get_fcn = _metagen_device_status_get_fcn) - _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_DEVICE, "DEVICE"), - _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_TYPE, "TYPE"), - _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_STATE, "STATE"), - _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_DBUS_PATH, "DBUS-PATH"), - _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CONNECTION, "CONNECTION"), - _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CON_UUID, "CON-UUID"), - _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CON_PATH, "CON-PATH"), + _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_DEVICE, "DEVICE"), + _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_TYPE, "TYPE"), + _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_STATE, "STATE"), + _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_IP4_CONNECTIVITY, "IP4-CONNECTIVITY"), + _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_IP6_CONNECTIVITY, "IP6-CONNECTIVITY"), + _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_DBUS_PATH, "DBUS-PATH"), + _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CONNECTION, "CONNECTION"), + _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CON_UUID, "CON-UUID"), + _METAGEN_DEVICE_STATUS (NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CON_PATH, "CON-PATH"), }; /*****************************************************************************/ @@ -155,6 +157,7 @@ _metagen_device_detail_general_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) NMActiveConnection *ac; NMDeviceState state; NMDeviceStateReason state_reason; + NMConnectivityState connectivity; const char *s; NMC_HANDLE_COLOR (NM_META_COLOR_NONE); @@ -194,6 +197,18 @@ _metagen_device_detail_general_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) state_reason, nmc_device_reason_to_string (state_reason), get_type)); + case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP4_CONNECTIVITY: + connectivity = nm_device_get_connectivity (d, AF_INET); + return (*out_to_free = nmc_meta_generic_get_enum_with_detail (NMC_META_GENERIC_GET_ENUM_TYPE_PARENTHESES, + connectivity, + nm_connectivity_to_string (connectivity), + get_type)); + case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP6_CONNECTIVITY: + connectivity = nm_device_get_connectivity (d, AF_INET6); + return (*out_to_free = nmc_meta_generic_get_enum_with_detail (NMC_META_GENERIC_GET_ENUM_TYPE_PARENTHESES, + connectivity, + nm_connectivity_to_string (connectivity), + get_type)); case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_UDI: return nm_device_get_udi (d); case NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP_IFACE: @@ -244,6 +259,8 @@ const NmcMetaGenericInfo *const metagen_device_detail_general[_NMC_GENERIC_INFO_ _METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_MTU, "MTU"), _METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_STATE, "STATE"), _METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_REASON, "REASON"), + _METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP4_CONNECTIVITY, "IP4-CONNECTIVITY"), + _METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP6_CONNECTIVITY, "IP6-CONNECTIVITY"), _METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_UDI, "UDI"), _METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP_IFACE, "IP-IFACE"), _METAGEN_DEVICE_DETAIL_GENERAL (NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IS_SOFTWARE, "IS-SOFTWARE"), @@ -680,7 +697,7 @@ usage (void) " disconnect <ifname> ...\n\n" " delete <ifname> ...\n\n" " monitor <ifname> ...\n\n" - " wifi [list [ifname <ifname>] [bssid <BSSID>]]\n\n" + " wifi [list [ifname <ifname>] [bssid <BSSID>] [--rescan yes|no|auto]]\n\n" " wifi connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>]\n" " [bssid <BSSID>] [name <name>] [private yes|no] [hidden yes|no]\n\n" " wifi hotspot [ifname <ifname>] [con-name <name>] [ssid <SSID>] [band a|bg] [channel <channel>] [password <password>]\n\n" @@ -815,22 +832,22 @@ usage_device_wifi (void) "\n" "Perform operation on Wi-Fi devices.\n" "\n" - "ARGUMENTS := [list [ifname <ifname>] [bssid <BSSID>]]\n" + "ARGUMENTS := [list [ifname <ifname>] [bssid <BSSID>] [--rescan yes|no|auto]]\n" "\n" "List available Wi-Fi access points. The 'ifname' and 'bssid' options can be\n" - "used to list APs for a particular interface, or with a specific BSSID.\n" + "used to list APs for a particular interface, or with a specific BSSID. The\n" + "--rescan flag tells whether a new Wi-Fi scan should be triggered.\n" "\n" "ARGUMENTS := connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>]\n" " [bssid <BSSID>] [name <name>] [private yes|no] [hidden yes|no]\n" "\n" - "Connect to a Wi-Fi network specified by SSID or BSSID. The command creates\n" - "a new connection and then activates it on a device. This is a command-line\n" - "counterpart of clicking an SSID in a GUI client. The command always creates\n" - "a new connection and thus it is mainly useful for connecting to new Wi-Fi\n" - "networks. If a connection for the network already exists, it is better to\n" - "bring up the existing profile as follows: nmcli con up id <name>. Note that\n" - "only open, WEP and WPA-PSK networks are supported at the moment. It is also\n" - "assumed that IP configuration is obtained via DHCP.\n" + "Connect to a Wi-Fi network specified by SSID or BSSID. The command finds a\n" + "matching connection or creates one and then activates it on a device. This\n" + "is a command-line counterpart of clicking an SSID in a GUI client. If a\n" + "connection for the network already exists, it is possible to bring up the\n" + "existing profile as follows: nmcli con up id <name>. Note that only open,\n" + "WEP and WPA-PSK networks are supported if no previous connection exists.\n" + "It is also assumed that IP configuration is obtained via DHCP.\n" "\n" "ARGUMENTS := hotspot [ifname <ifname>] [con-name <name>] [ssid <SSID>]\n" " [band a|bg] [channel <channel>] [password <password>]\n" @@ -879,77 +896,19 @@ compare_devices (const void *a, const void *b) { NMDevice *da = *(NMDevice **)a; NMDevice *db = *(NMDevice **)b; - NMActiveConnection *da_ac; - NMActiveConnection *db_ac; - NMIPConfig *da_ip; - NMIPConfig *db_ip; - int da_num_addrs; - int db_num_addrs; - int cmp; - - /* Sort by later device states first */ - cmp = nm_device_get_state (db) - nm_device_get_state (da); - if (cmp != 0) - return cmp; - - da_ac = nm_device_get_active_connection (da); - db_ac = nm_device_get_active_connection (db); - - /* Prioritize devices with active connections */ - if (da_ac) - cmp++; - if (db_ac) - cmp--; - if (cmp != 0) - return cmp; - - /* VPNs go on the top if possible */ - if (da_ac && !nm_active_connection_get_vpn (da_ac)) - cmp++; - if (db_ac && !nm_active_connection_get_vpn (db_ac)) - cmp--; - if (cmp != 0) - return cmp; - - /* Default devices are prioritized */ - if (da_ac && !nm_active_connection_get_default (da_ac)) - cmp++; - if (db_ac && !nm_active_connection_get_default (db_ac)) - cmp--; - if (cmp != 0) - return cmp; - - /* Default IPv6 devices are prioritized */ - if (da_ac && !nm_active_connection_get_default6 (da_ac)) - cmp++; - if (db_ac && !nm_active_connection_get_default6 (db_ac)) - cmp--; - if (cmp != 0) - return cmp; - - /* Sort by number of addresses. */ - da_ip = da_ac ? nm_active_connection_get_ip4_config (da_ac) : NULL; - da_num_addrs = da_ip ? nm_ip_config_get_addresses (da_ip)->len : 0; - db_ip = db_ac ? nm_active_connection_get_ip4_config (db_ac) : NULL; - db_num_addrs = db_ip ? nm_ip_config_get_addresses (db_ip)->len : 0; - - da_ip = da_ac ? nm_active_connection_get_ip6_config (da_ac) : NULL; - da_num_addrs += da_ip ? nm_ip_config_get_addresses (da_ip)->len : 0; - db_ip = db_ac ? nm_active_connection_get_ip6_config (db_ac) : NULL; - db_num_addrs += db_ip ? nm_ip_config_get_addresses (db_ip)->len : 0; - - cmp = db_num_addrs - da_num_addrs; - if (cmp != 0) - return cmp; - - /* Fall back to alphanumeric sort by description and interface. */ - cmp = g_strcmp0 (nm_device_get_type_description (da), - nm_device_get_type_description (db)); - if (cmp != 0) - return cmp; - - return g_strcmp0 (nm_device_get_iface (da), - nm_device_get_iface (db)); + NMActiveConnection *da_ac = nm_device_get_active_connection (da); + NMActiveConnection *db_ac = nm_device_get_active_connection (db); + + NM_CMP_DIRECT (nm_device_get_state (db), nm_device_get_state (da)); + NM_CMP_RETURN (nmc_active_connection_cmp (db_ac, da_ac)); + NM_CMP_DIRECT_STRCMP0 (nm_device_get_type_description (da), + nm_device_get_type_description (db)); + NM_CMP_DIRECT_STRCMP0 (nm_device_get_iface (da), + nm_device_get_iface (db)); + NM_CMP_DIRECT_STRCMP0 (nm_object_get_path (NM_OBJECT (da)), + nm_object_get_path (NM_OBJECT (db))); + + g_return_val_if_reached (0); } NMDevice ** @@ -1006,9 +965,11 @@ get_device_list (NmCli *nmc, int argc, char **argv) if (argc == 0) { if (nmc->ask) { - char *line = nmc_readline (PROMPT_INTERFACES); + gs_free char *line = NULL; + + line = nmc_readline (&nmc->nmc_config, + PROMPT_INTERFACES); nmc_string_to_arg_array (line, NULL, FALSE, &arg_arr, &arg_num); - g_free (line); arg_ptr = arg_arr; } if (arg_num == 0) { @@ -1063,8 +1024,10 @@ get_device (NmCli *nmc, int *argc, char ***argv, GError **error) int i; if (*argc == 0) { - if (nmc->ask) - ifname = ifname_ask = nmc_readline (PROMPT_INTERFACE); + if (nmc->ask) { + ifname = ifname_ask = nmc_readline (&nmc->nmc_config, + PROMPT_INTERFACE); + } if (!ifname_ask) { g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, @@ -1195,21 +1158,21 @@ fill_output_access_point (gpointer data, gpointer user_data) if ( (flags & NM_802_11_AP_FLAGS_PRIVACY) && (wpa_flags == NM_802_11_AP_SEC_NONE) && (rsn_flags == NM_802_11_AP_SEC_NONE)) { - g_string_append (security_str, _("WEP")); - g_string_append_c (security_str, ' '); + g_string_append (security_str, "WEP "); } if (wpa_flags != NM_802_11_AP_SEC_NONE) { - g_string_append (security_str, _("WPA1")); - g_string_append_c (security_str, ' '); + g_string_append (security_str, "WPA1 "); + } + if ( (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { + g_string_append (security_str, "WPA2 "); } - if (rsn_flags != NM_802_11_AP_SEC_NONE) { - g_string_append (security_str, _("WPA2")); - g_string_append_c (security_str, ' '); + if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) { + g_string_append (security_str, "WPA3 "); } if ( (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { - g_string_append (security_str, _("802.1X")); - g_string_append_c (security_str, ' '); + g_string_append (security_str, "802.1X "); } if (security_str->len > 0) @@ -1869,6 +1832,7 @@ typedef struct { NmCli *nmc; NMDevice *device; gboolean hotspot; + gboolean create; } AddAndActivateInfo; static void @@ -1879,47 +1843,29 @@ add_and_activate_cb (GObject *client, AddAndActivateInfo *info = (AddAndActivateInfo *) user_data; NmCli *nmc = info->nmc; NMDevice *device = info->device; - NMActiveConnectionState state; NMActiveConnection *active; GError *error = NULL; - active = nm_client_add_and_activate_connection_finish (NM_CLIENT (client), result, &error); + if (info->create) + active = nm_client_add_and_activate_connection_finish (NM_CLIENT (client), result, &error); + else + active = nm_client_activate_connection_finish (NM_CLIENT (client), result, &error); if (error) { if (info->hotspot) g_string_printf (nmc->return_text, _("Error: Failed to setup a Wi-Fi hotspot: %s"), error->message); - else + else if (info->create) g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: %s"), error->message); + else + g_string_printf (nmc->return_text, _("Error: Failed to activate connection: %s"), + error->message); g_error_free (error); nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; quit (); } else { - state = nm_active_connection_get_state (active); - - if (state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) { - if (info->hotspot) - g_string_printf (nmc->return_text, _("Error: Failed to setup a Wi-Fi hotspot")); - else - g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: Unknown error")); - nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; - g_object_unref (active); - quit (); - } - - if (nmc->nowait_flag || state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - /* User doesn't want to wait or already activated */ - if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) - nmc_terminal_erase_line (); - if (!info->hotspot) - g_print (_("Connection with UUID '%s' created and activated on device '%s'\n"), - nm_active_connection_get_uuid (active), nm_device_get_iface (device)); - else - g_print (_("Hotspot '%s' activated on device '%s'\n"), - nm_active_connection_get_id (active), nm_device_get_iface (device)); - } + if (nmc->nowait_flag) { g_object_unref (active); quit (); } else { @@ -1927,6 +1873,8 @@ add_and_activate_cb (GObject *client, g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), active); g_signal_connect (active, "notify::state", G_CALLBACK (active_state_cb), device); + connected_state_cb (device, active); + g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc); /* Exit if timeout expires */ if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) @@ -1970,13 +1918,13 @@ connect_device_cb (GObject *client, GAsyncResult *result, gpointer user_data) GError *error = NULL; const GPtrArray *devices; NMDevice *device; - NMDeviceState state; active = nm_client_activate_connection_finish (NM_CLIENT (client), result, &error); if (error) { /* If no connection existed for the device, create one and activate it */ if (g_error_matches (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION)) { + info->create = TRUE; create_connect_connection_for_device (info); return; } @@ -1999,27 +1947,24 @@ connect_device_cb (GObject *client, GAsyncResult *result, gpointer user_data) } device = g_ptr_array_index (devices, 0); - state = nm_device_get_state (device); - if (nmc->nowait_flag || state == NM_DEVICE_STATE_ACTIVATED) { - /* Don't want to wait or device already activated */ - if (state == NM_DEVICE_STATE_ACTIVATED && nmc->nmc_config.print_output == NMC_PRINT_PRETTY) { - nmc_terminal_erase_line (); - g_print (_("Device '%s' has been connected.\n"), nm_device_get_iface (device)); - } + if (nmc->nowait_flag) { g_object_unref (active); quit (); } else { if (nmc->secret_agent) { NMRemoteConnection *connection = nm_active_connection_get_connection (active); - nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (nmc->secret_agent), + nm_secret_agent_simple_enable (nmc->secret_agent, nm_connection_get_path (NM_CONNECTION (connection))); } g_object_ref (device); g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), active); g_signal_connect (active, "notify::state", G_CALLBACK (active_state_cb), device); + + connected_state_cb (device, active); + /* Start timer not to loop forever if "notify::state" signal is not issued */ g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc); } @@ -2518,7 +2463,7 @@ do_device_set (NmCli *nmc, int argc, char **argv) return error->code; } - if (!argc) { + if (!argc) { g_string_printf (nmc->return_text, _("Error: No property specified.")); return NMC_RESULT_ERROR_USER_INPUT; } @@ -2717,7 +2662,7 @@ find_wifi_device_by_iface (NMDevice **devices, const char *iface, int *idx) } /* - * Find AP on 'device' according to 'bssid' or 'ssid' parameter. + * Find AP on 'device' according to 'bssid' and 'ssid' parameters. * Returns: found AP or NULL */ static NMAccessPoint * @@ -2734,17 +2679,17 @@ find_ap_on_device (NMDevice *device, const char *bssid, const char *ssid, gboole NMAccessPoint *candidate_ap = g_ptr_array_index (aps, i); if (bssid) { - /* Parameter is BSSID */ const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap); + if (!candidate_bssid) + continue; + /* Compare BSSIDs */ if (complete) { if (g_str_has_prefix (candidate_bssid, bssid)) g_print ("%s\n", candidate_bssid); - } else if (strcmp (bssid, candidate_bssid) == 0) { - ap = candidate_ap; - break; - } + } else if (strcmp (bssid, candidate_bssid) != 0) + continue; } if (ssid) { @@ -2763,13 +2708,18 @@ find_ap_on_device (NMDevice *device, const char *bssid, const char *ssid, gboole if (complete) { if (g_str_has_prefix (ssid_tmp, ssid)) g_print ("%s\n", ssid_tmp); - } else if (strcmp (ssid, ssid_tmp) == 0) { - ap = candidate_ap; + } else if (strcmp (ssid, ssid_tmp) != 0) { g_free (ssid_tmp); - break; + continue; } g_free (ssid_tmp); } + + if (complete) + continue; + + ap = candidate_ap; + break; } return ap; @@ -3173,7 +3123,6 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingWireless *s_wifi; - NMSettingWirelessSecurity *s_wsec; AddAndActivateInfo *info; const char *param_user = NULL; const char *ifname = NULL; @@ -3189,6 +3138,10 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) int devices_idx; char *ssid_ask = NULL; char *passwd_ask = NULL; + const GPtrArray *avail_cons; + gboolean name_match = FALSE; + gboolean existing_con = FALSE; + int i; /* Set default timeout waiting for operation completion. */ if (nmc->timeout == -1) @@ -3211,7 +3164,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) g_assert (!nmc->complete); if (nmc->ask) { - ssid_ask = nmc_readline (_("SSID or BSSID: ")); + ssid_ask = nmc_readline (&nmc->nmc_config, _("SSID or BSSID: ")); param_user = ssid_ask ?: ""; bssid1_arr = nm_utils_hwaddr_atoba (param_user, ETH_ALEN); } @@ -3393,14 +3346,14 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) } /* Find an AP to connect to */ - ap = find_ap_on_device (device, bssid1_arr ? param_user : NULL, + ap = find_ap_on_device (device, bssid1_arr ? param_user : bssid, bssid1_arr ? NULL : param_user, FALSE); if (!ap && !ifname) { NMDevice *dev; /* AP not found, ifname was not specified, so try finding the AP on another device. */ while ((dev = find_wifi_device_by_iface (devices, NULL, &devices_idx)) != NULL) { - ap = find_ap_on_device (dev, bssid1_arr ? param_user : NULL, + ap = find_ap_on_device (dev, bssid1_arr ? param_user : bssid, bssid1_arr ? NULL : param_user, FALSE); if (ap) { device = dev; @@ -3418,45 +3371,75 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) goto finish; } - /* If there are some connection data from user, create a connection and - * fill them into proper settings. */ - if (con_name || private || bssid2_arr || password || hidden) - connection = nm_simple_connection_new (); + avail_cons = nm_device_get_available_connections (device); + for (i = 0; i < avail_cons->len; i++) { + NMRemoteConnection *avail_con = g_ptr_array_index (avail_cons, i); + const char *id = nm_connection_get_id (NM_CONNECTION (avail_con)); - if (con_name || private) { - s_con = (NMSettingConnection *) nm_setting_connection_new (); - nm_connection_add_setting (connection, NM_SETTING (s_con)); + if (con_name) { + if (!id || strcmp (id, con_name)) + continue; - /* Set user provided connection name */ - if (con_name) - g_object_set (s_con, NM_SETTING_CONNECTION_ID, con_name, NULL); + name_match = TRUE; + } - /* Connection will only be visible to this user when 'private' is specified */ - if (private) - nm_setting_connection_add_permission (s_con, "user", g_get_user_name (), NULL); + if (nm_access_point_connection_valid (ap, NM_CONNECTION (avail_con))) { + /* ap has been checked against bssid1, bssid2 and the ssid + * and now avail_con has been checked against ap. + */ + connection = NM_CONNECTION (avail_con); + existing_con = TRUE; + break; + } } - if (bssid2_arr || hidden) { - s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); - nm_connection_add_setting (connection, NM_SETTING (s_wifi)); - - /* 'bssid' parameter is used to restrict the connection only to the BSSID */ - if (bssid2_arr) - g_object_set (s_wifi, NM_SETTING_WIRELESS_BSSID, bssid2_arr, NULL); - - /* 'hidden' parameter is used to indicate that SSID is not broadcasted */ - if (hidden) { - GBytes *ssid = g_bytes_new (param_user, strlen (param_user)); - - g_object_set (s_wifi, - NM_SETTING_WIRELESS_SSID, ssid, - NM_SETTING_WIRELESS_HIDDEN, hidden, - NULL); - g_bytes_unref (ssid); - - /* Warn when the provided AP identifier looks like BSSID instead of SSID */ - if (bssid1_arr) - g_printerr (_("Warning: '%s' should be SSID for hidden APs; but it looks like a BSSID.\n"), - param_user); + + if (name_match && !existing_con) { + g_string_printf (nmc->return_text, _("Error: Connection '%s' exists but properties don't match."), con_name); + nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; + goto finish; + } + + if (!existing_con) { + /* If there are some connection data from user, create a connection and + * fill them into proper settings. */ + if (con_name || private || bssid2_arr || password || hidden) + connection = nm_simple_connection_new (); + + if (con_name || private) { + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + /* Set user provided connection name */ + if (con_name) + g_object_set (s_con, NM_SETTING_CONNECTION_ID, con_name, NULL); + + /* Connection will only be visible to this user when 'private' is specified */ + if (private) + nm_setting_connection_add_permission (s_con, "user", g_get_user_name (), NULL); + } + if (bssid2_arr || hidden) { + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + + /* 'bssid' parameter is used to restrict the connection only to the BSSID */ + if (bssid2_arr) + g_object_set (s_wifi, NM_SETTING_WIRELESS_BSSID, bssid2_arr, NULL); + + /* 'hidden' parameter is used to indicate that SSID is not broadcasted */ + if (hidden) { + GBytes *ssid = g_bytes_new (param_user, strlen (param_user)); + + g_object_set (s_wifi, + NM_SETTING_WIRELESS_SSID, ssid, + NM_SETTING_WIRELESS_HIDDEN, hidden, + NULL); + g_bytes_unref (ssid); + + /* Warn when the provided AP identifier looks like BSSID instead of SSID */ + if (bssid1_arr) + g_printerr (_("Warning: '%s' should be SSID for hidden APs; but it looks like a BSSID.\n"), + param_user); + } } } @@ -3469,15 +3452,38 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) if ( (ap_flags & NM_802_11_AP_FLAGS_PRIVACY) || ap_wpa_flags != NM_802_11_AP_SEC_NONE || ap_rsn_flags != NM_802_11_AP_SEC_NONE) { + const char *con_password = NULL; + NMSettingWirelessSecurity *s_wsec = NULL; + + if (connection) { + s_wsec = nm_connection_get_setting_wireless_security (connection); + if (s_wsec) { + if (ap_wpa_flags == NM_802_11_AP_SEC_NONE && ap_rsn_flags == NM_802_11_AP_SEC_NONE) { + /* WEP */ + con_password = nm_setting_wireless_security_get_wep_key (s_wsec, 0); + } else if ( (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE)) { + /* WPA PSK */ + con_password = nm_setting_wireless_security_get_psk (s_wsec); + } + } + } + /* Ask for missing password when one is expected and '--ask' is used */ - if (!password && nmc->ask) - password = passwd_ask = nmc_readline_echo (nmc->nmc_config.show_secrets, _("Password: ")); + if (!password && !con_password && nmc->ask) { + password = passwd_ask = nmc_readline_echo (&nmc->nmc_config, + nmc->nmc_config.show_secrets, + _("Password: ")); + } if (password) { if (!connection) connection = nm_simple_connection_new (); - s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new (); - nm_connection_add_setting (connection, NM_SETTING (s_wsec)); + if (!s_wsec) { + s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wsec)); + } if (ap_wpa_flags == NM_802_11_AP_SEC_NONE && ap_rsn_flags == NM_802_11_AP_SEC_NONE) { /* WEP */ @@ -3487,13 +3493,14 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) wep_passphrase ? NM_WEP_KEY_TYPE_PASSPHRASE: NM_WEP_KEY_TYPE_KEY, NULL); } else if ( (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) { + || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE)) { /* WPA PSK */ g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_PSK, password, NULL); } } } - // FIXME: WPA-Enterprise is not supported yet. + // FIXME: Creating WPA-Enterprise connections is not supported yet. // We are not able to determine and fill all the parameters for // 802.1X authentication automatically without user providing // the data. Adding nmcli options for the 8021x setting would @@ -3511,14 +3518,24 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) info->nmc = nmc; info->device = device; info->hotspot = FALSE; - - nm_client_add_and_activate_connection_async (nmc->client, - connection, - device, - nm_object_get_path (NM_OBJECT (ap)), - NULL, - add_and_activate_cb, - info); + info->create = !existing_con; + if (existing_con) { + nm_client_activate_connection_async (nmc->client, + connection, + device, + nm_object_get_path (NM_OBJECT (ap)), + NULL, + add_and_activate_cb, + info); + } else { + nm_client_add_and_activate_connection_async (nmc->client, + connection, + device, + nm_object_get_path (NM_OBJECT (ap)), + NULL, + add_and_activate_cb, + info); + } finish: if (bssid1_arr) diff --git a/clients/cli/general.c b/clients/cli/general.c index cb87c110..2c22bdc9 100644 --- a/clients/cli/general.c +++ b/clients/cli/general.c @@ -21,7 +21,6 @@ #include "general.h" -#include <string.h> #include <stdlib.h> #include "nm-common-macros.h" @@ -37,7 +36,7 @@ /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (nm_state_to_string_no_l10n, NMState, +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (nm_state_to_string, NMState, NM_UTILS_LOOKUP_DEFAULT (N_("unknown")), NM_UTILS_LOOKUP_ITEM (NM_STATE_ASLEEP, N_("asleep")), NM_UTILS_LOOKUP_ITEM (NM_STATE_CONNECTING, N_("connecting")), @@ -49,12 +48,6 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (nm_state_to_string_no_l10n, NMState, NM_UTILS_LOOKUP_ITEM_IGNORE (NM_STATE_UNKNOWN), ); -static const char * -nm_state_to_string (NMState state) -{ - return _(nm_state_to_string_no_l10n (state)); -} - static NMMetaColor state_to_color (NMState state) { @@ -78,21 +71,6 @@ state_to_color (NMState state) } } -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (nm_connectivity_to_string_no_l10n, NMConnectivityState, - NM_UTILS_LOOKUP_DEFAULT (N_("unknown")), - NM_UTILS_LOOKUP_ITEM (NM_CONNECTIVITY_NONE, N_("none")), - NM_UTILS_LOOKUP_ITEM (NM_CONNECTIVITY_PORTAL, N_("portal")), - NM_UTILS_LOOKUP_ITEM (NM_CONNECTIVITY_LIMITED, N_("limited")), - NM_UTILS_LOOKUP_ITEM (NM_CONNECTIVITY_FULL, N_("full")), - NM_UTILS_LOOKUP_ITEM_IGNORE (NM_CONNECTIVITY_UNKNOWN), -); - -static const char * -nm_connectivity_to_string (NMConnectivityState connectivity) -{ - return _(nm_connectivity_to_string_no_l10n (connectivity)); -} - static NMMetaColor connectivity_to_color (NMConnectivityState connectivity) { @@ -146,12 +124,14 @@ permission_to_string (NMClientPermission perm) return NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS; case NM_CLIENT_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK: return NM_AUTH_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK; + case NM_CLIENT_PERMISSION_WIFI_SCAN: + return NM_AUTH_PERMISSION_WIFI_SCAN; default: return _("unknown"); } } -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (permission_result_to_string_no_l10n, NMClientPermissionResult, +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (permission_result_to_string, NMClientPermissionResult, NM_UTILS_LOOKUP_DEFAULT (N_("unknown")), NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_YES, N_("yes")), NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_NO, N_("no")), @@ -192,7 +172,7 @@ _metagen_general_status_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STATE: state = nm_client_get_state (nmc->client); NMC_HANDLE_COLOR (state_to_color (state)); - value = nm_state_to_string_no_l10n (state); + value = nm_state_to_string (state); goto translate_and_out; case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_STARTUP: v_bool = nm_client_get_startup (nmc->client); @@ -202,7 +182,7 @@ _metagen_general_status_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_CONNECTIVITY: connectivity = nm_client_get_connectivity (nmc->client); NMC_HANDLE_COLOR (connectivity_to_color (connectivity)); - value = nm_connectivity_to_string_no_l10n (connectivity); + value = nm_connectivity_to_string (connectivity); goto translate_and_out; case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_NETWORKING: v_bool = nm_client_networking_get_enabled (nmc->client); @@ -221,7 +201,7 @@ _metagen_general_status_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) goto enabled_out; case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX_HW: case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIMAX: - /* deprected fields. Don't return anything. */ + /* deprecated fields. Don't return anything. */ return NULL; default: break; @@ -286,7 +266,7 @@ _metagen_general_permissions_get_fcn (NMC_META_GENERIC_INFO_GET_FCN_ARGS) case NMC_GENERIC_INFO_TYPE_GENERAL_PERMISSIONS_VALUE: perm_result = nm_client_get_permission_result (nmc->client, perm); NMC_HANDLE_COLOR (permission_result_to_color (perm_result)); - s = permission_result_to_string_no_l10n (perm_result); + s = permission_result_to_string (perm_result); if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) return _(s); return s; @@ -561,8 +541,7 @@ print_permissions (void *user_data) permissions[i++] = GINT_TO_POINTER (perm); permissions[i++] = NULL; - /* Optionally start paging the output. */ - nmc_terminal_spawn_pager (&nmc->nmc_config); + nm_cli_spawn_pager (nmc); if (!nmc_print (&nmc->nmc_config, permissions, @@ -998,7 +977,7 @@ do_radio_wifi (NmCli *nmc, int argc, char **argv) if (nmc->complete) return nmc->return_value; - /* no argument, show current WiFi state */ + /* no argument, show current Wi-Fi state */ nmc_switch_show (nmc, NMC_FIELDS_NM_WIFI, N_("Wi-Fi radio switch")); } else { if (nmc->complete) { @@ -1114,7 +1093,8 @@ client_connectivity (NMClient *client, GParamSpec *param, NmCli *nmc) g_object_get (client, NM_CLIENT_CONNECTIVITY, &connectivity, NULL); str = nmc_colorize (&nmc->nmc_config, connectivity_to_color (connectivity), - _("Connectivity is now '%s'\n"), nm_connectivity_to_string (connectivity)); + _("Connectivity is now '%s'\n"), + gettext (nm_connectivity_to_string (connectivity))); g_print ("%s", str); g_free (str); } @@ -1128,7 +1108,7 @@ client_state (NMClient *client, GParamSpec *param, NmCli *nmc) g_object_get (client, NM_CLIENT_STATE, &state, NULL); str = nmc_colorize (&nmc->nmc_config, state_to_color (state), _("Networkmanager is now in the '%s' state\n"), - nm_state_to_string (state)); + gettext (nm_state_to_string (state))); g_print ("%s", str); g_free (str); } @@ -1285,8 +1265,7 @@ do_overview (NmCli *nmc, int argc, char **argv) /* Register polkit agent */ nmc_start_polkit_agent_start_try (nmc); - /* Optionally start paging the output. */ - nmc_terminal_spawn_pager (&nmc->nmc_config); + nm_cli_spawn_pager (nmc); /* The VPN connections don't have devices (yet?). */ p = nm_client_get_active_connections (nmc->client); diff --git a/clients/cli/meson.build b/clients/cli/meson.build index c5669c96..11fe1cd1 100644 --- a/clients/cli/meson.build +++ b/clients/cli/meson.build @@ -3,7 +3,7 @@ name = 'nmcli' # FIXME: nmcli-completion should be renamed to nmcli install_data( 'nmcli-completion', - install_dir: join_paths(nm_datadir, 'bash-completion', 'completions') + install_dir: join_paths(nm_datadir, 'bash-completion', 'completions'), ) sources = files( @@ -15,7 +15,7 @@ sources = files( 'nmcli.c', 'polkit-agent.c', 'settings.c', - 'utils.c' + 'utils.c', ) deps = [ @@ -23,7 +23,7 @@ deps = [ libnmc_base_dep, libnmc_dep, nm_core_dep, - readline_dep + readline_dep, ] cflags = clients_cflags + [ @@ -43,5 +43,5 @@ executable( c_args: cflags, link_args: ldflags_linker_script_binary, link_depends: linker_script_binary, - install: true + install: true, ) diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c index bbfc310d..d7bc2a46 100644 --- a/clients/cli/nmcli.c +++ b/clients/cli/nmcli.c @@ -24,7 +24,6 @@ #include "nmcli.h" #include <stdio.h> -#include <string.h> #include <stdlib.h> #include <signal.h> #include <termios.h> @@ -245,19 +244,19 @@ 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" - " -c[olors] auto|yes|no whether to use colors in output\n" - " -f[ields] <field1,field2,...>|all|common specify fields to output\n" - " -g[et-values] <field1,field2,...>|all|common shortcut for -m tabular -t -f\n" - " -e[scape] yes|no escape columns separators in values\n" - " -a[sk] ask for missing parameters\n" - " -s[how-secrets] allow displaying passwords\n" - " -w[ait] <seconds> set timeout waiting for finishing operations\n" - " -v[ersion] show program version\n" - " -h[elp] print this help\n" + " -a, --ask ask for missing parameters\n" + " -c, --colors auto|yes|no whether to use colors in output\n" + " -e, --escape yes|no escape columns separators in values\n" + " -f, --fields <field,...>|all|common specify fields to output\n" + " -g, --get-values <field,...>|all|common shortcut for -m tabular -t -f\n" + " -h, --help print this help\n" + " -m, --mode tabular|multiline output mode\n" + " -o, --overview overview mode\n" + " -p, --pretty pretty output\n" + " -s, --show-secrets allow displaying passwords\n" + " -t, --terse terse output\n" + " -v, --version show program version\n" + " -w, --wait <seconds> set timeout waiting for finishing operations\n" "\n" "OBJECT\n" " g[eneral] NetworkManager's general status and operations\n" @@ -504,7 +503,7 @@ resolve_color_alias (const char *color) static const struct { const char *name; const char *alias; - } const aliases[] = { + } aliases[] = { { "reset", "0" }, { "bold", "1" }, { "white", "1;37" }, @@ -998,6 +997,14 @@ nmc_value_transforms_register (void) nmc_convert_bytes_to_string); } +void +nm_cli_spawn_pager (NmCli *nmc) +{ + if (nmc->pager_pid > 0) + return; + nmc->pager_pid = nmc_terminal_spawn_pager (&nmc->nmc_config); +} + static void nmc_cleanup (NmCli *nmc) { @@ -1005,15 +1012,15 @@ nmc_cleanup (NmCli *nmc) g_clear_object (&nmc->client); - g_string_free (nmc->return_text, TRUE); + if (nmc->return_text) + g_string_free (g_steal_pointer (&nmc->return_text), TRUE); if (nmc->secret_agent) { - /* Destroy secret agent if we have one. */ - nm_secret_agent_old_unregister (nmc->secret_agent, NULL, NULL); - g_object_unref (nmc->secret_agent); + nm_secret_agent_old_unregister (NM_SECRET_AGENT_OLD (nmc->secret_agent), NULL, NULL); + g_clear_object (&nmc->secret_agent); } - if (nmc->pwds_hash) - g_hash_table_destroy (nmc->pwds_hash); + + nm_clear_pointer (&nmc->pwds_hash, g_hash_table_destroy); nm_clear_g_free (&nmc->required_fields); diff --git a/clients/cli/nmcli.h b/clients/cli/nmcli.h index 28616855..cd50333a 100644 --- a/clients/cli/nmcli.h +++ b/clients/cli/nmcli.h @@ -20,7 +20,7 @@ #ifndef NMC_NMCLI_H #define NMC_NMCLI_H -#include "nm-secret-agent-old.h" +#include "nm-secret-agent-simple.h" #include "nm-meta-setting-desc.h" struct _NMPolkitListener; @@ -129,7 +129,7 @@ typedef struct _NmCli { int timeout; /* Operation timeout */ - NMSecretAgentOld *secret_agent; /* Secret agent */ + NMSecretAgentSimple *secret_agent; /* Secret agent */ GHashTable *pwds_hash; /* Hash table with passwords in passwd-file */ struct _NMPolkitListener *pk_listener; /* polkit agent listener */ @@ -167,6 +167,8 @@ void nmc_clear_sigint (void); void nmc_set_sigquit_internal (void); void nmc_exit (void); +void nm_cli_spawn_pager (NmCli *nmc); + void nmc_empty_output_fields (NmcOutputData *output_data); #define NMC_OUTPUT_DATA_DEFINE_SCOPED(out) \ diff --git a/clients/cli/polkit-agent.c b/clients/cli/polkit-agent.c index 338f0b15..accb567f 100644 --- a/clients/cli/polkit-agent.c +++ b/clients/cli/polkit-agent.c @@ -22,7 +22,6 @@ #include "polkit-agent.h" #include <stdio.h> -#include <string.h> #include <sys/types.h> #include <unistd.h> @@ -40,24 +39,25 @@ polkit_request (NMPolkitListener *listener, gboolean echo_on, gpointer user_data) { - char *response, *tmp, *p; + NmCli *nmc = user_data; g_print ("%s\n", message); g_print ("(action_id: %s)\n", action_id); /* Ask user for polkit authorization password */ if (user) { + gs_free char *tmp = NULL; + char *p; + /* chop of ": " if present */ tmp = g_strdup (request); p = strrchr (tmp, ':'); - if (p && !strcmp (p, ": ")) + if (p && nm_streq (p, ": ")) *p = '\0'; - response = nmc_readline_echo (echo_on, "%s (%s): ", tmp, user); - g_free (tmp); - } else - response = nmc_readline_echo (echo_on, "%s", request); + return nmc_readline_echo (&nmc->nmc_config, echo_on, "%s (%s): ", tmp, user); + } - return response; + return nmc_readline_echo (&nmc->nmc_config, echo_on, "%s", request); } static void diff --git a/clients/cli/settings.c b/clients/cli/settings.c index 2d231e1c..a04c8eb6 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -307,7 +307,8 @@ nmc_setting_connection_connect_handlers (NMSettingConnection *setting, NMConnect /*****************************************************************************/ static gboolean -_set_fcn_precheck_connection_secondaries (const char *value, +_set_fcn_precheck_connection_secondaries (NMClient *client, + const char *value, char **value_coerced, GError **error) { @@ -322,7 +323,7 @@ _set_fcn_precheck_connection_secondaries (const char *value, if (!strv0) return TRUE; - connections = nm_client_get_connections (nm_cli.client); + connections = nm_client_get_connections (client); strv = g_strdupv ((char **) strv0); for (iter = strv; *iter; iter++) { @@ -332,7 +333,7 @@ _set_fcn_precheck_connection_secondaries (const char *value, g_print (_("Warning: %s is not an UUID of any existing connection profile\n"), *iter); } else { - /* Currenly NM only supports VPN connections as secondaries */ + /* Currently NM only supports VPN connections as secondaries */ if (!nm_connection_is_type (con, NM_SETTING_VPN_SETTING_NAME)) { g_set_error (error, 1, 0, _("'%s' is not a VPN connection profile"), *iter); return FALSE; @@ -345,7 +346,7 @@ _set_fcn_precheck_connection_secondaries (const char *value, return FALSE; } - /* Currenly NM only supports VPN connections as secondaries */ + /* Currently NM only supports VPN connections as secondaries */ if (!nm_connection_is_type (con, NM_SETTING_VPN_SETTING_NAME)) { g_set_error (error, 1, 0, _("'%s' is not a VPN connection profile"), *iter); return FALSE; @@ -531,7 +532,7 @@ _set_fcn_call (const NMMetaPropertyInfo *property_info, * Returns: TRUE on success; FALSE on failure and sets error */ gboolean -nmc_setting_set_property (NMSetting *setting, const char *prop, const char *value, GError **error) +nmc_setting_set_property (NMClient *client, NMSetting *setting, const char *prop, const char *value, GError **error) { const NMMetaPropertyInfo *property_info; @@ -552,7 +553,7 @@ nmc_setting_set_property (NMSetting *setting, const char *prop, const char *valu if (nm_streq (property_info->property_name, NM_SETTING_CONNECTION_SECONDARIES)) { gs_free char *value_coerced = NULL; - if (!_set_fcn_precheck_connection_secondaries (value, &value_coerced, error)) + if (!_set_fcn_precheck_connection_secondaries (client, value, &value_coerced, error)) return FALSE; return _set_fcn_call (property_info, @@ -590,11 +591,11 @@ nmc_property_set_default_value (NMSetting *setting, const char *prop) } /* - * Generic function for reseting (single value) properties. + * Generic function for resetting (single value) properties. * * The function resets the property value to the default one. It respects * nmcli restrictions for changing properties. So if 'set_func' is NULL, - * reseting the value is denied. + * resetting the value is denied. * * Returns: TRUE on success; FALSE on failure and sets error */ diff --git a/clients/cli/settings.h b/clients/cli/settings.h index 7dad622b..4e7e38df 100644 --- a/clients/cli/settings.h +++ b/clients/cli/settings.h @@ -42,7 +42,8 @@ char *nmc_setting_get_property (NMSetting *setting, char *nmc_setting_get_property_parsable (NMSetting *setting, const char *prop, GError **error); -gboolean nmc_setting_set_property (NMSetting *setting, +gboolean nmc_setting_set_property (NMClient *client, + NMSetting *setting, const char *prop, const char *val, GError **error); diff --git a/clients/cli/utils.c b/clients/cli/utils.c index feb67221..0e74ba88 100644 --- a/clients/cli/utils.c +++ b/clients/cli/utils.c @@ -23,9 +23,7 @@ #include "utils.h" #include <stdio.h> -#include <string.h> #include <stdlib.h> -#include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -36,6 +34,7 @@ #include "nm-meta-setting-access.h" #include "common.h" +#include "nmcli.h" #include "settings.h" #define ML_HEADER_WIDTH 79 @@ -1100,7 +1099,7 @@ _print_fill (const NmcConfig *nmc_config, /* don't mark the entry for display. This is to shorten the output in case * the property is the default value. But we only do that, if the user * opts in to this behavior (-overview), or of the property marks itself - * elegible to be hidden. + * eligible to be hidden. * * In general, only new API shall mark itself eligible to be hidden. * Long established properties cannot, because it would be a change @@ -1275,7 +1274,7 @@ _print_do (const NmcConfig *nmc_config, title = header_cell->title; width1 = strlen (title); - width2 = nmc_string_screen_width (title, NULL); /* Width of the string (in screen colums) */ + width2 = nmc_string_screen_width (title, NULL); /* Width of the string (in screen columns) */ g_string_append_printf (str, "%-*s", (int) (header_cell->width + width1 - width2), title); g_string_append_c (str, ' '); /* Column separator */ table_width += header_cell->width + width1 - width2 + 1; @@ -1357,7 +1356,7 @@ _print_do (const NmcConfig *nmc_config, const PrintDataHeaderCell *header_cell = &header_row[i_col]; width1 = strlen (text); - width2 = nmc_string_screen_width (text, NULL); /* Width of the string (in screen colums) */ + width2 = nmc_string_screen_width (text, NULL); /* Width of the string (in screen columns) */ g_string_append_printf (str, "%-*s", (int) (header_cell->width + width1 - width2), text); g_string_append_c (str, ' '); /* Column separator */ table_width += header_cell->width + width1 - width2 + 1; @@ -1427,19 +1426,20 @@ pager_fallback (void) { char buf[64]; int rb; + int errsv; do { rb = read (STDIN_FILENO, buf, sizeof (buf)); if (rb == -1) { - if (errno == EINTR) { + errsv = errno; + if (errsv == EINTR) continue; - } else { - g_printerr (_("Error reading nmcli output: %s\n"), strerror (errno)); - _exit(EXIT_FAILURE); - } + g_printerr (_("Error reading nmcli output: %s\n"), nm_strerror_native (errsv)); + _exit(EXIT_FAILURE); } if (write (STDOUT_FILENO, buf, rb) == -1) { - g_printerr (_("Error writing nmcli output: %s\n"), strerror (errno)); + errsv = errno; + g_printerr (_("Error writing nmcli output: %s\n"), nm_strerror_native (errsv)); _exit(EXIT_FAILURE); } } while (rb > 0); @@ -1447,38 +1447,41 @@ pager_fallback (void) _exit(EXIT_SUCCESS); } -void +pid_t nmc_terminal_spawn_pager (const NmcConfig *nmc_config) { const char *pager = getenv ("PAGER"); + pid_t pager_pid; pid_t parent_pid; int fd[2]; + int errsv; - if ( nm_cli.nmc_config.in_editor - || nm_cli.pager_pid > 0 + if ( nmc_config->in_editor || nmc_config->print_output == NMC_PRINT_TERSE || !nmc_config->use_colors || g_strcmp0 (pager, "") == 0 || getauxval (AT_SECURE)) - return; + return 0; if (pipe (fd) == -1) { - g_printerr (_("Failed to create pager pipe: %s\n"), strerror (errno)); - return; + errsv = errno; + g_printerr (_("Failed to create pager pipe: %s\n"), nm_strerror_native (errsv)); + return 0; } parent_pid = getpid (); - nm_cli.pager_pid = fork (); - if (nm_cli.pager_pid == -1) { - g_printerr (_("Failed to fork pager: %s\n"), strerror (errno)); + pager_pid = fork (); + if (pager_pid == -1) { + errsv = errno; + g_printerr (_("Failed to fork pager: %s\n"), nm_strerror_native (errsv)); nm_close (fd[0]); nm_close (fd[1]); - return; + return 0; } /* In the child start the pager */ - if (nm_cli.pager_pid == 0) { + if (pager_pid == 0) { dup2 (fd[0], STDIN_FILENO); nm_close (fd[0]); nm_close (fd[1]); @@ -1516,13 +1519,18 @@ nmc_terminal_spawn_pager (const NmcConfig *nmc_config) } /* Return in the parent */ - if (dup2 (fd[1], STDOUT_FILENO) < 0) - g_printerr (_("Failed to duplicate pager pipe: %s\n"), strerror (errno)); - if (dup2 (fd[1], STDERR_FILENO) < 0) - g_printerr (_("Failed to duplicate pager pipe: %s\n"), strerror (errno)); + if (dup2 (fd[1], STDOUT_FILENO) < 0) { + errsv = errno; + g_printerr (_("Failed to duplicate pager pipe: %s\n"), nm_strerror_native (errsv)); + } + if (dup2 (fd[1], STDERR_FILENO) < 0) { + errsv = errno; + g_printerr (_("Failed to duplicate pager pipe: %s\n"), nm_strerror_native (errsv)); + } nm_close (fd[0]); nm_close (fd[1]); + return pager_pid; } /*****************************************************************************/ @@ -1589,8 +1597,7 @@ print_required_fields (const NmcConfig *nmc_config, gboolean field_names = of_flags & NMC_OF_FLAG_FIELD_NAMES; gboolean section_prefix = of_flags & NMC_OF_FLAG_SECTION_PREFIX; - /* Optionally start paging the output. */ - nmc_terminal_spawn_pager (nmc_config); + nm_cli_spawn_pager (&nm_cli); /* --- Main header --- */ if ( nmc_config->print_output == NMC_PRINT_PRETTY @@ -1730,7 +1737,7 @@ print_required_fields (const NmcConfig *nmc_config, g_string_append_c (str, ':'); /* Column separator */ } else { width1 = strlen (value); - width2 = nmc_string_screen_width (value, NULL); /* Width of the string (in screen colums) */ + width2 = nmc_string_screen_width (value, NULL); /* Width of the string (in screen columns) */ g_string_append_printf (str, "%-*s", field_values[idx].width + width1 - width2, strlen (value) > 0 ? value : not_set_str); g_string_append_c (str, ' '); /* Column separator */ table_width += field_values[idx].width + width1 - width2 + 1; diff --git a/clients/cli/utils.h b/clients/cli/utils.h index b2a3e5eb..b84b35bf 100644 --- a/clients/cli/utils.h +++ b/clients/cli/utils.h @@ -40,7 +40,7 @@ gboolean nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***a 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); +pid_t nmc_terminal_spawn_pager (const NmcConfig *nmc_config); 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); @@ -166,6 +166,8 @@ typedef enum { NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_DEVICE = 0, NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_TYPE, NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_STATE, + NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_IP4_CONNECTIVITY, + NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_IP6_CONNECTIVITY, NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_DBUS_PATH, NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CONNECTION, NMC_GENERIC_INFO_TYPE_DEVICE_STATUS_CON_UUID, @@ -184,6 +186,8 @@ typedef enum { NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_MTU, NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_STATE, NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_REASON, + NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP4_CONNECTIVITY, + NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP6_CONNECTIVITY, NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_UDI, NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IP_IFACE, NMC_GENERIC_INFO_TYPE_DEVICE_DETAIL_GENERAL_IS_SOFTWARE, |