diff options
Diffstat (limited to 'clients/cli')
| -rw-r--r-- | clients/cli/agent.c | 96 | ||||
| -rw-r--r-- | clients/cli/agent.h | 13 | ||||
| -rw-r--r-- | clients/cli/common.c | 77 | ||||
| -rw-r--r-- | clients/cli/common.h | 10 | ||||
| -rw-r--r-- | clients/cli/connections.c | 508 | ||||
| -rw-r--r-- | clients/cli/connections.h | 13 | ||||
| -rw-r--r-- | clients/cli/devices.c | 784 | ||||
| -rw-r--r-- | clients/cli/devices.h | 2 | ||||
| -rw-r--r-- | clients/cli/general.c | 532 | ||||
| -rw-r--r-- | clients/cli/general.h | 17 | ||||
| -rw-r--r-- | clients/cli/meson.build | 33 | ||||
| -rw-r--r-- | clients/cli/nmcli.c | 120 | ||||
| -rw-r--r-- | clients/cli/nmcli.h | 35 | ||||
| -rw-r--r-- | clients/cli/polkit-agent.c | 97 | ||||
| -rw-r--r-- | clients/cli/settings.c | 6 | ||||
| -rw-r--r-- | clients/cli/utils.c | 77 | ||||
| -rw-r--r-- | clients/cli/utils.h | 8 |
17 files changed, 1322 insertions, 1106 deletions
diff --git a/clients/cli/agent.c b/clients/cli/agent.c index f4057df9..f3707db7 100644 --- a/clients/cli/agent.c +++ b/clients/cli/agent.c @@ -5,8 +5,6 @@ #include "nm-default.h" -#include "agent.h" - #include <stdio.h> #include <stdlib.h> #include <readline/readline.h> @@ -16,6 +14,7 @@ #include "utils.h" #include "nm-secret-agent-simple.h" #include "polkit-agent.h" +#include "nm-polkit-listener.h" static void usage (void) @@ -122,12 +121,12 @@ secrets_requested (NMSecretAgentSimple *agent, success ? secrets : NULL); } -static NMCResultCode -do_agent_secret (NmCli *nmc, int argc, char **argv) +static void +do_agent_secret (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { next_arg (nmc, &argc, &argv, NULL); if (nmc->complete) - return nmc->return_value; + return; /* Create secret agent */ nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-agent"); @@ -145,76 +144,93 @@ do_agent_secret (NmCli *nmc, int argc, char **argv) g_string_printf (nmc->return_text, _("Error: secret agent initialization failed")); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; } +} - return nmc->return_value; +static void +polkit_registered (gpointer instance, + gpointer user_data) +{ + g_print (_("nmcli successfully registered as a polkit agent.\n")); +} + +static void +polkit_error (gpointer instance, + const char *error, + gpointer user_data) +{ + g_main_loop_quit (loop); } -static NMCResultCode -do_agent_polkit (NmCli *nmc, int argc, char **argv) +static void +do_agent_polkit (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { - GError *error = NULL; + gs_free_error GError *error = NULL; next_arg (nmc, &argc, &argv, NULL); if (nmc->complete) - return nmc->return_value; + return; - /* Initialize polkit agent */ if (!nmc_polkit_agent_init (nmc, TRUE, &error)) { g_dbus_error_strip_remote_error (error); - g_string_printf (nmc->return_text, _("Error: polkit agent initialization failed: %s"), + g_string_printf (nmc->return_text, + _("Error: polkit agent initialization failed: %s"), error->message); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - g_error_free (error); } else { /* We keep running */ nmc->should_wait++; - - g_print (_("nmcli successfully registered as a polkit agent.\n")); + g_signal_connect (nmc->pk_listener, + NM_POLKIT_LISTENER_SIGNAL_ERROR, + G_CALLBACK (polkit_error), + NULL); + g_signal_connect (nmc->pk_listener, + NM_POLKIT_LISTENER_SIGNAL_REGISTERED, + G_CALLBACK (polkit_registered), + NULL); + + /* keep running */ + nmc->should_wait++; } - - return nmc->return_value; } -static NMCResultCode -do_agent_all (NmCli *nmc, int argc, char **argv) +static void +do_agent_all (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { - NMCResultCode secret_res; + NMCResultCode r; next_arg (nmc, &argc, &argv, NULL); if (nmc->complete) - return nmc->return_value; + return; /* Run both secret and polkit agent */ - secret_res = do_agent_secret (nmc, argc, argv); - if (secret_res != NMC_RESULT_SUCCESS) { + do_agent_secret (cmd, nmc, argc, argv); + r = nmc->return_value; + if (r != NMC_RESULT_SUCCESS) { g_printerr ("%s\n", nmc->return_text->str); g_string_truncate (nmc->return_text, 0); + nmc->return_value = NMC_RESULT_SUCCESS; } - nmc->return_value = do_agent_polkit (nmc, argc, argv); + do_agent_polkit (cmd, nmc, argc, argv); if (nmc->return_value != NMC_RESULT_SUCCESS) { g_printerr ("%s\n", nmc->return_text->str); g_string_truncate (nmc->return_text, 0); } - if (nmc->return_value == NMC_RESULT_SUCCESS && secret_res != NMC_RESULT_SUCCESS) - nmc->return_value = secret_res; - - return nmc->return_value; + if (r != NMC_RESULT_SUCCESS) + nmc->return_value = r; } -static const NMCCommand agent_cmds[] = { - { "secret", do_agent_secret, usage_agent_secret, TRUE, TRUE }, - { "polkit", do_agent_polkit, usage_agent_polkit, TRUE, TRUE }, - { "all", do_agent_all, usage_agent_all, TRUE, TRUE }, - { NULL, do_agent_all, usage, TRUE, TRUE }, -}; - -NMCResultCode -do_agent (NmCli *nmc, int argc, char **argv) +void +nmc_command_func_agent (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { - next_arg (nmc, &argc, &argv, NULL); - nmc_do_cmd (nmc, agent_cmds, *argv, argc, argv); + static const NMCCommand cmds[] = { + { "secret", do_agent_secret, usage_agent_secret, TRUE, TRUE }, + { "polkit", do_agent_polkit, usage_agent_polkit, TRUE, TRUE }, + { "all", do_agent_all, usage_agent_all, TRUE, TRUE }, + { NULL, do_agent_all, usage, TRUE, TRUE }, + }; - return nmc->return_value; + next_arg (nmc, &argc, &argv, NULL); + nmc_do_cmd (nmc, cmds, *argv, argc, argv); } diff --git a/clients/cli/agent.h b/clients/cli/agent.h deleted file mode 100644 index aad56bba..00000000 --- a/clients/cli/agent.h +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#ifndef __NMC_AGENT_H__ -#define __NMC_AGENT_H__ - -#include "nmcli.h" - -NMCResultCode do_agent (NmCli *nmc, int argc, char **argv); - -#endif /* __NMC_AGENT_H__ */ diff --git a/clients/cli/common.c b/clients/cli/common.c index 04ccf8dc..93defe65 100644 --- a/clients/cli/common.c +++ b/clients/cli/common.c @@ -13,8 +13,11 @@ #include <readline/readline.h> #include <readline/history.h> +#include "nm-libnm-aux/nm-libnm-aux.h" + #include "nm-vpn-helpers.h" #include "nm-client-utils.h" +#include "nm-glib-aux/nm-secret-utils.h" #include "utils.h" @@ -730,7 +733,7 @@ get_secrets_from_user (const NmcConfig *nmc_config, /* No password provided, cancel the secrets. */ if (!pwd) return FALSE; - g_free (secret->value); + nm_free_secret (secret->value); secret->value = pwd; } return TRUE; @@ -861,7 +864,9 @@ readline_cb (char *line) } static gboolean -stdin_ready_cb (GIOChannel * io, GIOCondition condition, gpointer data) +stdin_ready_cb (int fd, + GIOCondition condition, + gpointer data) { rl_callback_read_char (); return TRUE; @@ -871,14 +876,17 @@ static char * nmc_readline_helper (const NmcConfig *nmc_config, const char *prompt) { - GIOChannel *io = NULL; - guint io_watch_id; + GSource *io_source; nmc_set_in_readline (TRUE); - io = g_io_channel_unix_new (STDIN_FILENO); - io_watch_id = g_io_add_watch (io, G_IO_IN, stdin_ready_cb, NULL); - g_io_channel_unref (io); + io_source = nm_g_unix_fd_source_new (STDIN_FILENO, + G_IO_IN, + G_PRIORITY_DEFAULT, + stdin_ready_cb, + NULL, + NULL); + g_source_attach (io_source, NULL); read_again: rl_string = NULL; @@ -927,7 +935,8 @@ read_again: rl_string = NULL; } - g_source_remove (io_watch_id); + nm_clear_g_source_inst (&io_source); + nmc_set_in_readline (FALSE); return rl_string; @@ -1003,7 +1012,7 @@ nmc_readline_echo (const NmcConfig *nmc_config, va_list args; gs_free char *prompt = NULL; char *str; - HISTORY_STATE *saved_history; + nm_auto_free HISTORY_STATE *saved_history = NULL; HISTORY_STATE passwd_history = { 0, }; va_start (args, prompt_fmt); @@ -1016,6 +1025,10 @@ nmc_readline_echo (const NmcConfig *nmc_config, if (!echo_on) { saved_history = history_get_history_state (); history_set_history_state (&passwd_history); + /* stifling history is important as it tells readline to + * not store anything, otherwise sensitive data could be + * leaked */ + stifle_history (0); rl_redisplay_function = nmc_secret_redisplay; } @@ -1105,7 +1118,7 @@ nmc_rl_gen_func_ifnames (const char *text, int state) const char **ifnames; char *ret; - devices = nm_client_get_devices (nm_cli.client); + devices = nm_client_get_devices (nm_cli_global_readline->client); if (devices->len == 0) return NULL; @@ -1206,7 +1219,7 @@ typedef struct { } CmdCall; static void -call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, char **argv); +call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, const char *const*argv); static void got_client (GObject *source_object, GAsyncResult *res, gpointer user_data) @@ -1216,25 +1229,31 @@ got_client (GObject *source_object, GAsyncResult *res, gpointer user_data) CmdCall *call = user_data; NmCli *nmc; + nm_assert (NM_IS_CLIENT (source_object)); + task = g_steal_pointer (&call->task); nmc = g_task_get_task_data (task); nmc->should_wait--; - nmc->client = nm_client_new_finish (res, &error); - if (!nmc->client) { + if (!g_async_initable_init_finish (G_ASYNC_INITABLE (source_object), + res, + &error)) { + g_object_unref (source_object); g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_UNKNOWN, _("Error: Could not create NMClient object: %s."), error->message); } else { - call_cmd (nmc, g_steal_pointer (&task), call->cmd, call->argc, call->argv); + nmc->client = NM_CLIENT (source_object); + call_cmd (nmc, g_steal_pointer (&task), call->cmd, call->argc, (const char *const*) call->argv); } - g_slice_free (CmdCall, call); + g_strfreev (call->argv); + nm_g_slice_free (call); } static void -call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, char **argv) +call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, const char *const*argv) { CmdCall *call; @@ -1245,7 +1264,7 @@ call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, char **argv) g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_NM_NOT_RUNNING, _("Error: NetworkManager is not running.")); } else { - nmc->return_value = cmd->func (nmc, argc, argv); + cmd->func (cmd, nmc, argc, argv); g_task_return_boolean (task, TRUE); } @@ -1254,12 +1273,18 @@ call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, char **argv) nm_assert (nmc->client == NULL); nmc->should_wait++; - call = g_slice_new0 (CmdCall); - call->cmd = cmd; - call->argc = argc; - call->argv = argv; - call->task = task; - nm_client_new_async (NULL, got_client, call); + call = g_slice_new (CmdCall); + *call = (CmdCall) { + .cmd = cmd, + .argc = argc, + .argv = nm_utils_strv_dup ((char **) argv, argc, TRUE), + .task = task, + }; + nmc_client_new_async (NULL, + got_client, + call, + NM_CLIENT_INSTANCE_FLAGS, (guint) NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS, + NULL); } } @@ -1291,7 +1316,7 @@ nmc_complete_help (const char *prefix) * no callback to free the memory in (for simplicity). */ void -nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char **argv) +nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, const char *const*argv) { const NMCCommand *c; gs_unref_object GTask *task = NULL; @@ -1327,7 +1352,7 @@ nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char c->usage (); g_task_return_boolean (task, TRUE); } else { - call_cmd (nmc, g_steal_pointer (&task), c, argc, argv); + call_cmd (nmc, g_steal_pointer (&task), c, argc, (const char *const*) argv); } } else if (cmd) { /* Not a known command. */ @@ -1340,7 +1365,7 @@ nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char } } else if (c->func) { /* No command, run the default handler. */ - call_cmd (nmc, g_steal_pointer (&task), c, argc, argv); + call_cmd (nmc, g_steal_pointer (&task), c, argc, (const char *const*) argv); } else { /* No command and no default handler. */ g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, diff --git a/clients/cli/common.h b/clients/cli/common.h index f8fad8c6..243a2098 100644 --- a/clients/cli/common.h +++ b/clients/cli/common.h @@ -62,15 +62,7 @@ int nmc_rl_set_deftext (void); char *nmc_parse_lldp_capabilities (guint value); -typedef struct { - const char *cmd; - NMCResultCode (*func) (NmCli *nmc, int argc, char **argv); - void (*usage) (void); - gboolean needs_client; - gboolean needs_nm_running; -} NMCCommand; - -void nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char **argv); +void nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, const char *const*argv); void nmc_complete_strv (const char *prefix, gssize nargs, const char *const*args); diff --git a/clients/cli/connections.c b/clients/cli/connections.c index e13ae9ac..0e4a95e6 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -62,7 +62,8 @@ typedef struct _OptionInfo { /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (active_connection_state_to_string, NMActiveConnectionState, +static +NM_UTILS_LOOKUP_STR_DEFINE (active_connection_state_to_string, NMActiveConnectionState, NM_UTILS_LOOKUP_DEFAULT (N_("unknown")), NM_UTILS_LOOKUP_ITEM (NM_ACTIVE_CONNECTION_STATE_ACTIVATING, N_("activating")), NM_UTILS_LOOKUP_ITEM (NM_ACTIVE_CONNECTION_STATE_ACTIVATED, N_("activated")), @@ -71,7 +72,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (active_connection_state_to_string, NMActiveCo NM_UTILS_LOOKUP_ITEM_IGNORE (NM_ACTIVE_CONNECTION_STATE_UNKNOWN), ) -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (vpn_connection_state_to_string, NMVpnConnectionState, +static +NM_UTILS_LOOKUP_STR_DEFINE (vpn_connection_state_to_string, NMVpnConnectionState, NM_UTILS_LOOKUP_DEFAULT (N_("unknown")), NM_UTILS_LOOKUP_ITEM (NM_VPN_CONNECTION_STATE_PREPARE, N_("VPN connecting (prepare)")), NM_UTILS_LOOKUP_ITEM (NM_VPN_CONNECTION_STATE_NEED_AUTH, N_("VPN connecting (need authentication)")), @@ -421,7 +423,7 @@ _metagen_con_show_row_data_init_primary_active (MetagenConShowRowData *row_data) g_object_unref (row_data->primary_active); row_data->primary_active = g_object_ref (best_ac); } - g_clear_pointer (&row_data->all_active, g_ptr_array_unref); + nm_clear_pointer (&row_data->all_active, g_ptr_array_unref); } static void @@ -434,7 +436,7 @@ _metagen_con_show_row_data_destroy (gpointer data) g_clear_object (&row_data->connection); g_clear_object (&row_data->primary_active); - g_clear_pointer (&row_data->all_active, g_ptr_array_unref); + nm_clear_pointer (&row_data->all_active, g_ptr_array_unref); g_slice_free (MetagenConShowRowData, row_data); } @@ -855,6 +857,7 @@ const NmcMetaGenericInfo *const metagen_con_active_vpn[_NMC_GENERIC_INFO_TYPE_CO NM_SETTING_MACSEC_SETTING_NAME"," \ NM_SETTING_MACVLAN_SETTING_NAME"," \ NM_SETTING_VXLAN_SETTING_NAME"," \ + NM_SETTING_VRF_SETTING_NAME"," \ NM_SETTING_WPAN_SETTING_NAME","\ NM_SETTING_6LOWPAN_SETTING_NAME","\ NM_SETTING_WIREGUARD_SETTING_NAME","\ @@ -1111,6 +1114,10 @@ usage_connection_modify (void) "The '+' sign allows appending items instead of overwriting the whole value.\n" "The '-' sign allows removing selected items instead of the whole value.\n" "\n" + "ARGUMENTS := remove <setting>\n" + "\n" + "Remove a setting from the connection profile.\n" + "\n" "Examples:\n" "nmcli con mod home-wifi wifi.ssid rakosnicek\n" "nmcli con mod em1-1 ipv4.method manual ipv4.addr \"192.168.1.2/24, 10.10.1.5/8\"\n" @@ -1118,7 +1125,8 @@ usage_connection_modify (void) "nmcli con mod em1-1 -ipv4.dns 1\n" "nmcli con mod em1-1 -ipv6.addr \"abbe::cafe/56\"\n" "nmcli con mod bond0 +bond.options mii=500\n" - "nmcli con mod bond0 -bond.options downdelay\n\n")); + "nmcli con mod bond0 -bond.options downdelay\n" + "nmcli con mod em1-1 remove sriov\n\n")); } static void @@ -1348,9 +1356,9 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc) const char *base_hdr = _("Connection profile details"); gboolean was_output = FALSE; - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) + if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) fields_str = fields_common; - else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) + else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0) fields_str = fields_all; else fields_str = nmc->required_fields; @@ -1380,9 +1388,13 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc) for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) row[i].info = (const NMMetaAbstractInfo *) &nm_meta_setting_infos_editor[i]; - print_required_fields (&nmc->nmc_config, NMC_OF_FLAG_MAIN_HEADER_ONLY, - out_indices, header_name, - 0, row); + print_required_fields (&nmc->nmc_config, + &nmc->pager_data, + NMC_OF_FLAG_MAIN_HEADER_ONLY, + out_indices, + header_name, + 0, + row); } /* Loop through the required settings and print them. */ @@ -1436,8 +1448,8 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) const char *base_hdr = _("Activate connection details"); gboolean was_output = FALSE; - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) { - } else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) { + if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) { + } else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0) { } else fields_str = nmc->required_fields; @@ -1465,9 +1477,13 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) for (i = 0; nmc_fields_con_active_details_groups[i]; i++) row[i].info = (const NMMetaAbstractInfo *) nmc_fields_con_active_details_groups[i]; - print_required_fields (&nmc->nmc_config, NMC_OF_FLAG_MAIN_HEADER_ONLY, - out_indices, header_name, - 0, row); + print_required_fields (&nmc->nmc_config, + &nmc->pager_data, + NMC_OF_FLAG_MAIN_HEADER_ONLY, + out_indices, + header_name, + 0, + row); } /* Loop through the groups and print them. */ @@ -1500,7 +1516,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) } /* IP4 */ - if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[1]->name) == 0) { + if (g_ascii_strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[1]->name) == 0) { gboolean b1 = FALSE; NMIPConfig *cfg4 = nm_active_connection_get_ip4_config (acon); @@ -1509,7 +1525,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) } /* DHCP4 */ - if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[2]->name) == 0) { + if (g_ascii_strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[2]->name) == 0) { gboolean b1 = FALSE; NMDhcpConfig *dhcp4 = nm_active_connection_get_dhcp4_config (acon); @@ -1518,7 +1534,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) } /* IP6 */ - if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[3]->name) == 0) { + if (g_ascii_strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[3]->name) == 0) { gboolean b1 = FALSE; NMIPConfig *cfg6 = nm_active_connection_get_ip6_config (acon); @@ -1527,7 +1543,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc) } /* DHCP6 */ - if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[4]->name) == 0) { + if (g_ascii_strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name, nmc_fields_con_active_details_groups[4]->name) == 0) { gboolean b1 = FALSE; NMDhcpConfig *dhcp6 = nm_active_connection_get_dhcp6_config (acon); @@ -1594,13 +1610,13 @@ split_required_fields_for_con_show (const char *input, if (dot) *dot = '\0'; - is_all = !dot && strcasecmp (s_mutable, "all") == 0; - is_common = !dot && strcasecmp (s_mutable, "common") == 0; + is_all = !dot && g_ascii_strcasecmp (s_mutable, "all") == 0; + is_common = !dot && g_ascii_strcasecmp (s_mutable, "common") == 0; found = FALSE; for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { if ( is_all || is_common - || !strcasecmp (s_mutable, nm_meta_setting_infos[i].setting_name)) { + || !g_ascii_strcasecmp (s_mutable, nm_meta_setting_infos[i].setting_name)) { if (dot) *dot = '.'; g_string_append (str1, s_mutable); @@ -1614,7 +1630,7 @@ split_required_fields_for_con_show (const char *input, for (i = 0; nmc_fields_con_active_details_groups[i]; i++) { if ( is_all || is_common - || !strcasecmp (s_mutable, nmc_fields_con_active_details_groups[i]->name)) { + || !g_ascii_strcasecmp (s_mutable, nmc_fields_con_active_details_groups[i]->name)) { if (dot) *dot = '.'; g_string_append (str2, s_mutable); @@ -1626,9 +1642,9 @@ split_required_fields_for_con_show (const char *input, if (!found) { if (dot) *dot = '.'; - if (!strcasecmp (s_mutable, CON_SHOW_DETAIL_GROUP_PROFILE)) + if (!g_ascii_strcasecmp (s_mutable, CON_SHOW_DETAIL_GROUP_PROFILE)) group_profile = TRUE; - else if (!strcasecmp (s_mutable, CON_SHOW_DETAIL_GROUP_ACTIVE)) + else if (!g_ascii_strcasecmp (s_mutable, CON_SHOW_DETAIL_GROUP_ACTIVE)) group_active = TRUE; else { gs_free char *allowed1 = nm_meta_abstract_infos_get_names_str ((const NMMetaAbstractInfo *const*) nm_meta_setting_infos_editor_p (), NULL); @@ -1960,7 +1976,7 @@ parse_preferred_connection_order (const char *order, GError **error) static NMConnection * get_connection (NmCli *nmc, int *argc, - char ***argv, + const char *const**argv, const char **out_selector, const char **out_value, GPtrArray **out_result, @@ -2011,8 +2027,8 @@ get_connection (NmCli *nmc, return connection; } -static NMCResultCode -do_connections_show (NmCli *nmc, int argc, char **argv) +static void +do_connections_show (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { gs_free_error GError *err = NULL; gs_free char *profile_flds = NULL; @@ -2055,9 +2071,9 @@ do_connections_show (NmCli *nmc, int argc, char **argv) if (nmc->complete) goto finish; - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) + if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) fields_str = NMC_FIELDS_CON_SHOW_COMMON; - else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) { + else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0) { } else fields_str = nmc->required_fields; @@ -2085,7 +2101,7 @@ do_connections_show (NmCli *nmc, int argc, char **argv) } } - nm_cli_spawn_pager (nmc); + nm_cli_spawn_pager (&nmc->nmc_config, &nmc->pager_data); items = con_show_get_items (nmc, active_only, show_active_fields, order); g_ptr_array_add (items, NULL); @@ -2118,7 +2134,7 @@ do_connections_show (NmCli *nmc, int argc, char **argv) * option after the connection ids */ if (!nmc->nmc_config.show_secrets && !nmc->complete) { int argc_cp = argc; - char **argv_cp = argv; + const char *const*argv_cp = argv; do { if (NM_IN_STRSET (*argv_cp, "id", "uuid", "path", "filename", "apath")) { @@ -2268,7 +2284,6 @@ finish: g_string_printf (nmc->return_text, _("Error: %s."), err->message); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; } - return nmc->return_value; } static NMActiveConnection * @@ -2838,8 +2853,8 @@ nmc_activate_connection (NmCli *nmc, return TRUE; } -static NMCResultCode -do_connection_up (NmCli *nmc, int argc, char **argv) +static void +do_connection_up (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMConnection *connection = NULL; const char *ifname = NULL; @@ -2847,9 +2862,9 @@ do_connection_up (NmCli *nmc, int argc, char **argv) const char *nsp = NULL; const char *pwds = NULL; gs_free_error GError *error = NULL; - char **arg_arr = NULL; + gs_strfreev char **arg_arr = NULL; int arg_num; - char ***argv_ptr; + const char *const**argv_ptr; int *argc_ptr; /* @@ -2872,7 +2887,7 @@ do_connection_up (NmCli *nmc, int argc, char **argv) line = nmc_readline (&nmc->nmc_config, PROMPT_CONNECTION); nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num); - argv_ptr = &arg_arr; + argv_ptr = (const char *const**) &arg_arr; argc_ptr = &arg_num; } @@ -2880,7 +2895,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv) connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, NULL, NULL, &error); if (!connection) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); - return error->code; + nmc->return_value = error->code; + return; } } @@ -2893,7 +2909,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } ifname = *argv; @@ -2905,7 +2922,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } ap = *argv; @@ -2917,7 +2935,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (argc == 1 && nmc->complete) @@ -2927,14 +2946,15 @@ do_connection_up (NmCli *nmc, int argc, char **argv) } else if (!nmc->complete) { g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } next_arg (nmc, &argc, &argv, NULL); } if (nmc->complete) - return nmc->return_value; + return; /* Use nowait_flag instead of should_wait because exiting has to be postponed till * active_connection_state_cb() is called. That gives NM time to check our permissions @@ -2947,14 +2967,13 @@ do_connection_up (NmCli *nmc, int argc, char **argv) g_string_printf (nmc->return_text, _("Error: %s."), error->message); nmc->should_wait--; - return error->code; + nmc->return_value = error->code; + return; } /* Start progress indication */ if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) progress_id = g_timeout_add (120, progress_cb, _("preparing")); - - return nmc->return_value; } /*****************************************************************************/ @@ -3096,14 +3115,14 @@ connection_op_timeout_cb (gpointer user_data) return G_SOURCE_REMOVE; } -static NMCResultCode -do_connection_down (NmCli *nmc, int argc, char **argv) +static void +do_connection_down (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMActiveConnection *active; ConnectionCbInfo *info = NULL; const GPtrArray *active_cons; gs_strfreev char **arg_arr = NULL; - char **arg_ptr; + const char *const*arg_ptr; int arg_num; guint i; gs_unref_ptrarray GPtrArray *found_active_cons = NULL; @@ -3125,11 +3144,12 @@ do_connection_down (NmCli *nmc, int argc, char **argv) line = nmc_readline (&nmc->nmc_config, PROMPT_ACTIVE_CONNECTIONS); nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num); - arg_ptr = arg_arr; + arg_ptr = (const char *const*) arg_arr; } if (arg_num == 0) { g_string_printf (nmc->return_text, _("Error: No connection specified.")); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } } @@ -3147,7 +3167,8 @@ do_connection_down (NmCli *nmc, int argc, char **argv) arg_ptr++; if (!arg_num) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } } @@ -3168,12 +3189,13 @@ do_connection_down (NmCli *nmc, int argc, char **argv) if (!found_active_cons) { g_string_printf (nmc->return_text, _("Error: no active connection provided.")); - return NMC_RESULT_ERROR_NOT_FOUND; + nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; + return; } nm_assert (found_active_cons->len > 0); if (nmc->complete) - return nmc->return_value; + return; if (nmc->timeout > 0) { nmc->should_wait++; @@ -3210,8 +3232,6 @@ do_connection_down (NmCli *nmc, int argc, char **argv) } } } - - return nmc->return_value; } /*****************************************************************************/ @@ -3699,7 +3719,7 @@ prompt_yes_no (gboolean default_yes, char *delim) } static NMSetting * -is_setting_valid (NMConnection *connection, const NMMetaSettingValidPartItem *const*valid_settings_main, const NMMetaSettingValidPartItem *const*valid_settings_slave, char *setting) +is_setting_valid (NMConnection *connection, const NMMetaSettingValidPartItem *const*valid_settings_main, const NMMetaSettingValidPartItem *const*valid_settings_slave, const char *setting) { const char *setting_name; @@ -3834,7 +3854,7 @@ _meta_abstract_complete (const NMMetaAbstractInfo *abstract_info, const char *te values = nm_meta_abstract_info_complete (abstract_info, nmc_meta_environment, - nmc_meta_environment_arg, + (gpointer) nmc_meta_environment_arg, &ctx, text, NULL, @@ -4634,7 +4654,7 @@ complete_option (NmCli *nmc, const NMMetaAbstractInfo *abstract_info, const char values = nm_meta_abstract_info_complete (abstract_info, nmc_meta_environment, - nmc_meta_environment_arg, + (gpointer) nmc_meta_environment_arg, &ctx, prefix, &complete_filename, @@ -4659,6 +4679,27 @@ complete_option (NmCli *nmc, const NMMetaAbstractInfo *abstract_info, const char } static void +complete_existing_setting (NmCli *nmc, NMConnection *connection, const char *prefix) +{ + gs_free NMSetting **settings = NULL; + const NMMetaSettingInfoEditor *editor; + guint i; + + settings = nm_connection_get_settings (connection, NULL); + for (i = 0; settings && settings[i]; i++) { + editor = nm_meta_setting_info_editor_find_by_setting (settings[i]); + + if (!prefix || g_str_has_prefix (editor->general->setting_name, prefix)) + g_print ("%s\n", editor->general->setting_name); + + if (editor->alias) { + if (!prefix || g_str_has_prefix (editor->alias, prefix)) + g_print ("%s\n", editor->alias); + } + } +} + +static void complete_property (NmCli *nmc, const char *setting_name, const char *property, const char *prefix, NMConnection *connection) { const NMMetaPropertyInfo *property_info; @@ -4671,7 +4712,25 @@ complete_property (NmCli *nmc, const char *setting_name, const char *property, c /*****************************************************************************/ static gboolean -get_value (const char **value, int *argc, char ***argv, const char *option, GError **error) +connection_remove_setting (NMConnection *connection, NMSetting *setting, GError **error) +{ + gboolean mandatory; + + g_return_val_if_fail (setting, FALSE); + + mandatory = is_setting_mandatory (connection, setting); + if (!mandatory) { + nm_connection_remove_setting (connection, G_OBJECT_TYPE (setting)); + return TRUE; + } + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: setting '%s' is mandatory and cannot be removed."), + nm_setting_get_name (setting)); + return FALSE; +} + +static gboolean +get_value (const char **value, int *argc, const char *const**argv, const char *option, GError **error) { if (!**argv) { g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, @@ -4691,11 +4750,12 @@ get_value (const char **value, int *argc, char ***argv, const char *option, GErr } gboolean -nmc_read_connection_properties (NmCli *nmc, - NMConnection *connection, - int *argc, - char ***argv, - GError **error) +nmc_process_connection_properties (NmCli *nmc, + NMConnection *connection, + int *argc, + const char *const**argv, + gboolean allow_setting_removal, + GError **error) { /* First check if we have a slave-type, as this would mean we will not * have ip properties but possibly others, slave-type specific. @@ -4729,7 +4789,53 @@ nmc_read_connection_properties (NmCli *nmc, default: modifier = NM_META_ACCESSOR_MODIFIER_SET; option = option_orig; break; } - if ((tmp = strchr (option, '.'))) { + if ( allow_setting_removal + && modifier == NM_META_ACCESSOR_MODIFIER_SET + && nm_streq (option, "remove")) { + NMSetting *ss; + const char *setting_name; + + (*argc)--; + (*argv)++; + + if (*argc == 1 && nmc->complete) { + complete_existing_setting (nmc, connection, value); + return TRUE; + } + + if (!*argc) { + g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: missing setting.")); + return FALSE; + } + + setting_name = **argv; + (*argc)--; + (*argv)++; + + ss = is_setting_valid (connection, + type_settings, + slv_settings, + setting_name); + if (!ss) { + if (check_valid_name (setting_name, + type_settings, + slv_settings, + NULL)) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Setting '%s' is not present in the connection."), + setting_name); + } else { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: invalid setting argument '%s'."), + setting_name); + } + return FALSE; + } + + if (!connection_remove_setting (connection, ss, error)) + return FALSE; + } else if ((tmp = strchr (option, '.'))) { gs_free char *option_sett = g_strndup (option, tmp - option); const char *option_prop = &tmp[1]; const char *option_sett_expanded; @@ -4823,8 +4929,12 @@ nmc_read_connection_properties (NmCli *nmc, } if (!chosen) { - if (*argc == 1 && nmc->complete) + if (*argc == 1 && nmc->complete) { + if ( allow_setting_removal + && g_str_has_prefix ("remove", option)) + g_print ("remove\n"); complete_property_name (nmc, connection, modifier, option, NULL); + } g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, _("Error: invalid <setting>.<property> '%s'."), option); return FALSE; @@ -4844,7 +4954,6 @@ nmc_read_connection_properties (NmCli *nmc, if (!set_option (nmc, connection, chosen, value, error)) return FALSE; } - } while (*argc); return TRUE; @@ -5243,8 +5352,8 @@ again: return TRUE; } -static NMCResultCode -do_connection_add (NmCli *nmc, int argc, char **argv) +static void +do_connection_add (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; @@ -5267,7 +5376,7 @@ do_connection_add (NmCli *nmc, int argc, char **argv) read_properties: g_clear_error (&error); /* Get the arguments from the command line if any */ - if (argc && !nmc_read_connection_properties (nmc, connection, &argc, &argv, &error)) { + if (argc && !nmc_process_connection_properties (nmc, connection, &argc, &argv, FALSE, &error)) { if (g_strcmp0 (*argv, "--") == 0 && !seen_dash_dash) { /* This is for compatibility with older nmcli that required * options and properties to be separated with "--" */ @@ -5401,7 +5510,6 @@ read_properties: finish: reset_options (); - return nmc->return_value; } /*****************************************************************************/ @@ -5730,7 +5838,7 @@ gen_vpn_uuids (const char *text, int state) const char **uuids; char *ret; - connections = nm_client_get_connections (nm_cli.client); + connections = nm_client_get_connections (nm_cli_global_readline->client); if (connections->len < 1) return NULL; @@ -5747,7 +5855,7 @@ gen_vpn_ids (const char *text, int state) const char **ids; char *ret; - connections = nm_client_get_connections (nm_cli.client); + connections = nm_client_get_connections (nm_cli_global_readline->client); if (connections->len < 1) return NULL; @@ -6878,23 +6986,6 @@ print_setting_description (NMSetting *setting) g_strfreev (all_props); } -static gboolean -connection_remove_setting (NMConnection *connection, NMSetting *setting) -{ - gboolean mandatory; - - g_return_val_if_fail (setting, FALSE); - - mandatory = is_setting_mandatory (connection, setting); - if (!mandatory) { - nm_connection_remove_setting (connection, G_OBJECT_TYPE (setting)); - return TRUE; - } - g_print (_("Error: setting '%s' is mandatory and cannot be removed.\n"), - nm_setting_get_name (setting)); - return FALSE; -} - static void editor_show_status_line (NMConnection *connection, gboolean dirty, gboolean temp) { @@ -7632,8 +7723,12 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t ss = menu_ctx.curr_setting; if (descr_all) { + gs_free_error GError *local = NULL; + /* Remove setting from the connection */ - connection_remove_setting (connection, ss); + if (!connection_remove_setting (connection, ss, &local)) + g_print ("%s\n", local->message); + if (ss == menu_ctx.curr_setting) { /* If we removed the setting we are in, go up */ menu_switch_to_level0 (&nmc->nmc_config, &menu_ctx, BASE_PROMPT); @@ -7664,8 +7759,11 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t valid_settings_slave, cmd_arg_p); if (s_tmp) { + gs_free_error GError *local = NULL; + /* Remove setting from the connection */ - connection_remove_setting (connection, s_tmp); + if (!connection_remove_setting (connection, s_tmp, &local)) + g_print ("%s\n", local->message); /* coverity[copy_paste_error] - suppress Coverity COPY_PASTE_ERROR defect */ if (ss == menu_ctx.curr_setting) { @@ -7919,7 +8017,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t connection_changed = FALSE; } - source = g_timeout_source_new (10 * NM_UTILS_MSEC_PER_SECOND); + source = g_timeout_source_new (10 * NM_UTILS_MSEC_PER_SEC); g_source_set_callback (source, editor_save_timeout, &timeout, NULL); g_source_attach (source, g_main_loop_get_context (loop)); @@ -8259,8 +8357,8 @@ nmc_complete_connection_type (const char *prefix) } } -static NMCResultCode -do_connection_edit (NmCli *nmc, int argc, char **argv) +static void +do_connection_edit (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { const GPtrArray *connections; gs_unref_object NMConnection *connection = NULL; @@ -8295,7 +8393,8 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) else { if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, &error)) { g_string_assign (nmc->return_text, error->message); - return error->code; + nmc->return_value = error->code; + return; } } @@ -8325,7 +8424,8 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) } else { g_string_printf (nmc->return_text, _("Error: only one of 'id', 'filename', uuid, or 'path' can be provided.")); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } } @@ -8335,11 +8435,12 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) found_con = nmc_find_connection (connections, selector, con, NULL, nmc->complete); if (nmc->complete) - return nmc->return_value; + return; if (!found_con) { g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), con); - return NMC_RESULT_ERROR_NOT_FOUND; + nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; + return; } /* Duplicate the connection and use that so that we need not @@ -8374,7 +8475,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) if (nmc->complete) { if (type && argc == 0) nmc_complete_connection_type (type); - return nmc->return_value; + return; } connection_type = check_valid_name_toplevel (type, &slave_type, &err1); @@ -8450,7 +8551,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv) nm_clear_g_free (&nmc_tab_completion.con_type); nmc_tab_completion.connection = NULL; - return nmc->return_value; + return; } static void @@ -8478,10 +8579,8 @@ modify_connection_cb (GObject *connection, quit (); } -static NMCResultCode -do_connection_modify (NmCli *nmc, - int argc, - char **argv) +static void +do_connection_modify (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMConnection *connection = NULL; NMRemoteConnection *rc = NULL; @@ -8496,7 +8595,8 @@ do_connection_modify (NmCli *nmc, connection = get_connection (nmc, &argc, &argv, NULL, NULL, NULL, &error); if (!connection) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); - return error->code; + nmc->return_value = error->code; + return; } rc = nm_client_get_connection_by_uuid (nmc->client, @@ -8504,21 +8604,21 @@ do_connection_modify (NmCli *nmc, if (!rc) { g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), nm_connection_get_uuid (connection)); - return NMC_RESULT_ERROR_NOT_FOUND; + nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; + return; } - if (!nmc_read_connection_properties (nmc, NM_CONNECTION (rc), &argc, &argv, &error)) { + if (!nmc_process_connection_properties (nmc, NM_CONNECTION (rc), &argc, &argv, TRUE, &error)) { g_string_assign (nmc->return_text, error->message); - return error->code; + nmc->return_value = error->code; + return; } if (nmc->complete) - return nmc->return_value; + return; update_connection (rc, temporary, modify_connection_cb, nmc); nmc->should_wait++; - - return nmc->return_value; } static void @@ -8548,8 +8648,8 @@ clone_connection_cb (GObject *client, quit (); } -static NMCResultCode -do_connection_clone (NmCli *nmc, int argc, char **argv) +static void +do_connection_clone (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMConnection *connection = NULL; gs_unref_object NMConnection *new_connection = NULL; @@ -8557,9 +8657,9 @@ do_connection_clone (NmCli *nmc, int argc, char **argv) gs_free char *new_name_free = NULL; gs_free char *uuid = NULL; gboolean temporary = FALSE; - char **arg_arr = NULL; + gs_strfreev char **arg_arr = NULL; int arg_num; - char ***argv_ptr; + const char *const**argv_ptr; int *argc_ptr; GError *error = NULL; @@ -8580,18 +8680,19 @@ do_connection_clone (NmCli *nmc, int argc, char **argv) line = nmc_readline (&nmc->nmc_config, PROMPT_CONNECTION); nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num); - argv_ptr = &arg_arr; + argv_ptr = (const char *const**) &arg_arr; argc_ptr = &arg_num; } connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, NULL, NULL, &error); if (!connection) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); - return error->code; + nmc->return_value = error->code; + return; } if (nmc->complete) - return nmc->return_value; + return; if (argv[0]) new_name = *argv; @@ -8600,12 +8701,14 @@ do_connection_clone (NmCli *nmc, int argc, char **argv) _("New connection name: ")); } else { g_string_printf (nmc->return_text, _("Error: <new name> argument is missing.")); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (next_arg (nmc->ask ? NULL : nmc, argc_ptr, argv_ptr, NULL) == 0) { g_string_printf (nmc->return_text, _("Error: unknown extra argument: '%s'."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } new_connection = nm_simple_connection_new_clone (connection); @@ -8624,8 +8727,6 @@ do_connection_clone (NmCli *nmc, int argc, char **argv) clone_connection_cb, _add_connection_info_new (nmc, connection, new_connection)); nmc->should_wait++; - - return nmc->return_value; } static void @@ -8649,13 +8750,13 @@ delete_cb (GObject *con, GAsyncResult *result, gpointer user_data) } } -static NMCResultCode -do_connection_delete (NmCli *nmc, int argc, char **argv) +static void +do_connection_delete (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMConnection *connection; ConnectionCbInfo *info = NULL; gs_strfreev char **arg_arr = NULL; - char **arg_ptr; + const char *const*arg_ptr; guint i; int arg_num; nm_auto_free_gstring GString *invalid_cons = NULL; @@ -8679,7 +8780,7 @@ do_connection_delete (NmCli *nmc, int argc, char **argv) line = nmc_readline (&nmc->nmc_config, PROMPT_CONNECTIONS); nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num); - arg_ptr = arg_arr; + arg_ptr = (const char *const*) arg_arr; } if (arg_num == 0) { g_string_printf (nmc->return_text, _("Error: No connection specified.")); @@ -8750,7 +8851,6 @@ finish: invalid_cons->str); nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; } - return nmc->return_value; } static void @@ -8795,8 +8895,8 @@ connection_removed (NMClient *client, NMRemoteConnection *con, NmCli *nmc) connection_unwatch (nmc, connection); } -static NMCResultCode -do_connection_monitor (NmCli *nmc, int argc, char **argv) +static void +do_connection_monitor (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { GError *error = NULL; guint i; @@ -8817,7 +8917,8 @@ do_connection_monitor (NmCli *nmc, int argc, char **argv) if (!nmc->complete) g_printerr (_("Error: %s.\n"), error->message); g_string_printf (nmc->return_text, _("Error: not all connections found.")); - return error->code; + nmc->return_value = error->code; + return; } if (nmc->complete) @@ -8828,7 +8929,7 @@ do_connection_monitor (NmCli *nmc, int argc, char **argv) } if (nmc->complete) - return nmc->return_value; + return; for (i = 0; i < connections->len; i++) connection_watch (nmc, connections->pdata[i]); @@ -8840,19 +8941,17 @@ do_connection_monitor (NmCli *nmc, int argc, char **argv) } g_signal_connect (nmc->client, NM_CLIENT_CONNECTION_REMOVED, G_CALLBACK (connection_removed), nmc); - - return NMC_RESULT_SUCCESS; } -static NMCResultCode -do_connection_reload (NmCli *nmc, int argc, char **argv) +static void +do_connection_reload (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { gs_unref_variant GVariant *result = NULL; gs_free_error GError *error = NULL; next_arg (nmc, &argc, &argv, NULL); if (nmc->complete) - return nmc->return_value; + return; result = nmc_dbus_call_sync (nmc, "/org/freedesktop/NetworkManager/Settings", @@ -8866,33 +8965,31 @@ do_connection_reload (NmCli *nmc, int argc, char **argv) nmc_error_get_simple_message (error)); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; } - - return nmc->return_value; } -static NMCResultCode -do_connection_load (NmCli *nmc, int argc, char **argv) +static void +do_connection_load (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { GError *error = NULL; - char **filenames, **failures = NULL; + gs_free const char **filenames = NULL; + gs_strfreev char **failures = NULL; int i; next_arg (nmc, &argc, &argv, NULL); if (argc == 0) { g_string_printf (nmc->return_text, _("Error: No connection specified.")); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } - if (nmc->complete) - return NMC_RESULT_COMPLETE_FILE; + if (nmc->complete) { + nmc->return_value = NMC_RESULT_COMPLETE_FILE; + return; + } - filenames = g_new (char *, argc + 1); - for (i = 0; i < argc; i++) - filenames[i] = argv[i]; - filenames[i] = NULL; + filenames = (const char **) nm_utils_strv_dup ((char **) argv, argc, FALSE); - nm_client_load_connections (nmc->client, filenames, &failures, NULL, &error); - g_free (filenames); + nm_client_load_connections (nmc->client, (char **) filenames, &failures, NULL, &error); if (error) { g_string_printf (nmc->return_text, _("Error: failed to load connection: %s."), nmc_error_get_simple_message (error)); @@ -8903,16 +9000,13 @@ do_connection_load (NmCli *nmc, int argc, char **argv) if (failures) { for (i = 0; failures[i]; i++) g_printerr (_("Could not load file '%s'\n"), failures[i]); - g_strfreev (failures); } - - return nmc->return_value; } #define PROMPT_IMPORT_FILE N_("File to import: ") -static NMCResultCode -do_connection_import (NmCli *nmc, int argc, char **argv) +static void +do_connection_import (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { gs_free_error GError *error = NULL; const char *type = NULL, *filename = NULL; @@ -8943,7 +9037,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv) filename = nm_strstrip (filename_ask); } else { g_string_printf (nmc->return_text, _("Error: No arguments provided.")); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } } @@ -8959,7 +9054,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if ( argc == 1 @@ -8980,7 +9076,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (argc == 1 && nmc->complete) nmc->return_value = NMC_RESULT_COMPLETE_FILE; @@ -8990,22 +9087,25 @@ do_connection_import (NmCli *nmc, int argc, char **argv) g_printerr (_("Warning: 'file' already specified, ignoring extra one.\n")); } else { g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } next_arg (nmc, &argc, &argv, NULL); } if (nmc->complete) - return nmc->return_value; + return; if (!type) { g_string_printf (nmc->return_text, _("Error: 'type' argument is required.")); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (!filename) { g_string_printf (nmc->return_text, _("Error: 'file' argument is required.")); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (nm_streq (type, "wireguard")) @@ -9014,7 +9114,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv) 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); - return NMC_RESULT_ERROR_UNKNOWN; + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return; } /* Import VPN configuration */ @@ -9022,7 +9123,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv) if (!plugin) { g_string_printf (nmc->return_text, _("Error: failed to load VPN plugin: %s."), error->message); - return NMC_RESULT_ERROR_UNKNOWN; + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return; } connection = nm_vpn_editor_plugin_import (plugin, filename, &error); @@ -9031,7 +9133,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv) if (!connection) { g_string_printf (nmc->return_text, _("Error: failed to import '%s': %s."), filename, error->message); - return NMC_RESULT_ERROR_UNKNOWN; + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return; } add_connection (nmc->client, @@ -9040,12 +9143,10 @@ do_connection_import (NmCli *nmc, int argc, char **argv) add_connection_cb, _add_connection_info_new (nmc, NULL, connection)); nmc->should_wait++; - - return nmc->return_value; } -static NMCResultCode -do_connection_export (NmCli *nmc, int argc, char **argv) +static void +do_connection_export (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMConnection *connection = NULL; const char *out_name = NULL; @@ -9055,9 +9156,9 @@ do_connection_export (NmCli *nmc, int argc, char **argv) NMVpnEditorPlugin *plugin; gs_free_error GError *error = NULL; char tmpfile[] = "/tmp/nmcli-export-temp-XXXXXX"; - char **arg_arr = NULL; + gs_strfreev char **arg_arr = NULL; int arg_num; - char ***argv_ptr; + const char *const**argv_ptr; int *argc_ptr; next_arg (nmc, &argc, &argv, NULL); @@ -9073,7 +9174,7 @@ do_connection_export (NmCli *nmc, int argc, char **argv) line = nmc_readline (&nmc->nmc_config, PROMPT_VPN_CONNECTION); nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num); - argv_ptr = &arg_arr; + argv_ptr = (const char *const**) &arg_arr; argc_ptr = &arg_num; } @@ -9085,7 +9186,7 @@ do_connection_export (NmCli *nmc, int argc, char **argv) } if (nmc->complete) - return nmc->return_value; + return; out_name = *argv; @@ -9155,7 +9256,6 @@ do_connection_export (NmCli *nmc, int argc, char **argv) finish: if (!out_name && path) unlink (path); - return nmc->return_value; } static char * @@ -9166,7 +9266,7 @@ gen_func_connection_names (const char *text, int state) const char **connection_names; char *ret; - connections = nm_client_get_connections (nm_cli.client); + connections = nm_client_get_connections (nm_cli_global_readline->client); if (connections->len == 0) return NULL; @@ -9189,10 +9289,10 @@ gen_func_active_connection_names (const char *text, int state) const char **connections; char *ret; - if (!nm_cli.client) + if (!nm_cli_global_readline->client) return NULL; - acs = nm_client_get_active_connections (nm_cli.client); + acs = nm_client_get_active_connections (nm_cli_global_readline->client); if (!acs || acs->len == 0) return NULL; @@ -9243,46 +9343,42 @@ nmcli_con_tab_completion (const char *text, int start, int end) if (generator_func) match_array = rl_completion_matches (text, generator_func); - g_clear_pointer (&nmc_tab_completion.words, g_strfreev); + nm_clear_pointer (&nmc_tab_completion.words, g_strfreev); return match_array; } -static const NMCCommand connection_cmds[] = { - { "show", do_connections_show, usage_connection_show, TRUE, TRUE }, - { "up", do_connection_up, usage_connection_up, TRUE, TRUE }, - { "down", do_connection_down, usage_connection_down, TRUE, TRUE }, - { "add", do_connection_add, usage_connection_add, TRUE, TRUE }, - { "edit", do_connection_edit, usage_connection_edit, TRUE, TRUE }, - { "delete", do_connection_delete, usage_connection_delete, TRUE, TRUE }, - { "reload", do_connection_reload, usage_connection_reload, FALSE, FALSE }, - { "load", do_connection_load, usage_connection_load, TRUE, TRUE }, - { "modify", do_connection_modify, usage_connection_modify, TRUE, TRUE }, - { "clone", do_connection_clone, usage_connection_clone, TRUE, TRUE }, - { "import", do_connection_import, usage_connection_import, TRUE, TRUE }, - { "export", do_connection_export, usage_connection_export, TRUE, TRUE }, - { "monitor", do_connection_monitor, usage_connection_monitor, TRUE, TRUE }, - { NULL, do_connections_show, usage, TRUE, TRUE }, -}; +void +nmc_command_func_connection (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) +{ + static const NMCCommand cmds[] = { + { "show", do_connections_show, usage_connection_show, TRUE, TRUE }, + { "up", do_connection_up, usage_connection_up, TRUE, TRUE }, + { "down", do_connection_down, usage_connection_down, TRUE, TRUE }, + { "add", do_connection_add, usage_connection_add, TRUE, TRUE }, + { "edit", do_connection_edit, usage_connection_edit, TRUE, TRUE }, + { "delete", do_connection_delete, usage_connection_delete, TRUE, TRUE }, + { "reload", do_connection_reload, usage_connection_reload, FALSE, FALSE }, + { "load", do_connection_load, usage_connection_load, TRUE, TRUE }, + { "modify", do_connection_modify, usage_connection_modify, TRUE, TRUE }, + { "clone", do_connection_clone, usage_connection_clone, TRUE, TRUE }, + { "import", do_connection_import, usage_connection_import, TRUE, TRUE }, + { "export", do_connection_export, usage_connection_export, TRUE, TRUE }, + { "monitor",do_connection_monitor, usage_connection_monitor, TRUE, TRUE }, + { NULL, do_connections_show, usage, TRUE, TRUE }, + }; -/* Entry point function for connections-related commands: 'nmcli connection' */ -NMCResultCode -do_connections (NmCli *nmc, int argc, char **argv) -{ next_arg (nmc, &argc, &argv, NULL); - /* Register polkit agent */ nmc_start_polkit_agent_start_try (nmc); /* Set completion function for 'nmcli con' */ rl_attempted_completion_function = nmcli_con_tab_completion; - nmc_do_cmd (nmc, connection_cmds, *argv, argc, argv); - - return nmc->return_value; + nmc_do_cmd (nmc, cmds, *argv, argc, argv); } void monitor_connections (NmCli *nmc) { - do_connection_monitor (nmc, 0, NULL); + do_connection_monitor (NULL, nmc, 0, NULL); } diff --git a/clients/cli/connections.h b/clients/cli/connections.h index 7fa9d448..79359a1f 100644 --- a/clients/cli/connections.h +++ b/clients/cli/connections.h @@ -8,16 +8,15 @@ #include "nmcli.h" -NMCResultCode do_connections (NmCli *nmc, int argc, char **argv); - void monitor_connections (NmCli *nmc); gboolean -nmc_read_connection_properties (NmCli *nmc, - NMConnection *connection, - int *argc, - char ***argv, - GError **error); +nmc_process_connection_properties (NmCli *nmc, + NMConnection *connection, + int *argc, + const char *const**argv, + gboolean allow_remove_setting, + GError **error); NMMetaColor nmc_active_connection_state_to_color (NMActiveConnectionState state); diff --git a/clients/cli/devices.c b/clients/cli/devices.c index c99efd0d..4ea4e772 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -11,13 +11,13 @@ #include <stdlib.h> #include <readline/readline.h> -#include "nm-secret-agent-simple.h" +#include "nm-glib-aux/nm-secret-utils.h" +#include "common.h" +#include "connections.h" #include "nm-client-utils.h" - +#include "nm-secret-agent-simple.h" #include "polkit-agent.h" #include "utils.h" -#include "common.h" -#include "connections.h" /* define some prompts */ #define PROMPT_INTERFACE _("Interface: ") @@ -26,9 +26,9 @@ /*****************************************************************************/ static char * -ap_wpa_rsn_flags_to_string (NM80211ApSecurityFlags flags) +ap_wpa_rsn_flags_to_string (NM80211ApSecurityFlags flags, NMMetaAccessorGetType get_type) { - char *flags_str[13]; + char *flags_str[16]; int i = 0; if (flags & NM_802_11_AP_SEC_PAIR_WEP40) @@ -53,13 +53,19 @@ ap_wpa_rsn_flags_to_string (NM80211ApSecurityFlags flags) flags_str[i++] = "802.1X"; if (flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) flags_str[i++] = "sae"; + if (flags & NM_802_11_AP_SEC_KEY_MGMT_OWE) + flags_str[i++] = "owe"; + /* Make sure you grow flags_str when adding items here. */ + nm_assert (i < G_N_ELEMENTS (flags_str)); - if (i == 0) - flags_str[i++] = _("(none)"); + if (i == 0) { + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) + return g_strdup (_("(none)")); + return g_strdup ("(none)"); + } flags_str[i] = NULL; - return g_strjoinv (" ", flags_str); } @@ -990,11 +996,11 @@ nmc_complete_device (NMClient *client, const char *prefix, gboolean wifi_only) } static GSList * -get_device_list (NmCli *nmc, int argc, char **argv) +get_device_list (NmCli *nmc, int argc, const char *const*argv) { int arg_num = argc; - char **arg_arr = NULL; - char **arg_ptr = argv; + gs_strfreev char **arg_arr = NULL; + const char *const*arg_ptr = argv; NMDevice **devices; GSList *queue = NULL; NMDevice *device; @@ -1007,7 +1013,7 @@ get_device_list (NmCli *nmc, int argc, char **argv) line = nmc_readline (&nmc->nmc_config, PROMPT_INTERFACES); nmc_string_to_arg_array (line, NULL, FALSE, &arg_arr, &arg_num); - arg_ptr = arg_arr; + arg_ptr = (const char *const*) arg_arr; } if (arg_num == 0) { g_string_printf (nmc->return_text, _("Error: No interface specified.")); @@ -1053,7 +1059,7 @@ error: } static NMDevice * -get_device (NmCli *nmc, int *argc, char ***argv, GError **error) +get_device (NmCli *nmc, int *argc, const char *const**argv, GError **error) { gs_free NMDevice **devices = NULL; gs_free char *ifname_ask = NULL; @@ -1098,30 +1104,30 @@ compare_aps (gconstpointer a, gconstpointer b, gpointer user_data) { NMAccessPoint *apa = *(NMAccessPoint **)a; NMAccessPoint *apb = *(NMAccessPoint **)b; - int cmp; - cmp = nm_access_point_get_strength (apb) - nm_access_point_get_strength (apa); - if (cmp != 0) - return cmp; + NM_CMP_DIRECT (nm_access_point_get_strength (apb), nm_access_point_get_strength (apa)); + NM_CMP_DIRECT (nm_access_point_get_frequency (apa), nm_access_point_get_frequency (apb)); + NM_CMP_DIRECT (nm_access_point_get_max_bitrate (apb), nm_access_point_get_max_bitrate (apa)); - cmp = nm_access_point_get_frequency (apa) - nm_access_point_get_frequency (apb); - if (cmp != 0) - return cmp; + /* as fallback, just give it some stable order and use the D-Bus path (literally). */ + NM_CMP_DIRECT_STRCMP0 (nm_object_get_path (NM_OBJECT (apa)), + nm_object_get_path (NM_OBJECT (apb))); - return nm_access_point_get_max_bitrate (apb) - nm_access_point_get_max_bitrate (apa); + return 0; } static GPtrArray * sort_access_points (const GPtrArray *aps) { GPtrArray *sorted; - int i; + guint i; g_return_val_if_fail (aps, NULL); sorted = g_ptr_array_sized_new (aps->len); + g_ptr_array_set_free_func (sorted, nm_g_object_unref); for (i = 0; i < aps->len; i++) - g_ptr_array_add (sorted, aps->pdata[i]); + g_ptr_array_add (sorted, g_object_ref (aps->pdata[i])); g_ptr_array_sort_with_data (sorted, compare_aps, NULL); return sorted; } @@ -1186,8 +1192,8 @@ fill_output_access_point (gpointer data, gpointer user_data) freq_str = g_strdup_printf (_("%u MHz"), freq); bitrate_str = g_strdup_printf (_("%u Mbit/s"), bitrate/1000); strength_str = g_strdup_printf ("%u", strength); - wpa_flags_str = ap_wpa_rsn_flags_to_string (wpa_flags); - rsn_flags_str = ap_wpa_rsn_flags_to_string (rsn_flags); + wpa_flags_str = ap_wpa_rsn_flags_to_string (wpa_flags, NM_META_ACCESSOR_GET_TYPE_PRETTY); + rsn_flags_str = ap_wpa_rsn_flags_to_string (rsn_flags, NM_META_ACCESSOR_GET_TYPE_PRETTY); sig_bars = nmc_wifi_strength_bars (strength); security_str = g_string_new (NULL); @@ -1207,6 +1213,9 @@ fill_output_access_point (gpointer data, gpointer user_data) if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) { g_string_append (security_str, "WPA3 "); } + if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_OWE) { + g_string_append (security_str, "OWE "); + } 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 "); @@ -1331,7 +1340,7 @@ print_bond_bridge_info (NMDevice *device, g_ptr_array_add (out.output_data, arr); print_data_prepare_width (out.output_data); - print_data (&nmc->nmc_config, out_indices, NULL, 0, &out); + print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out); g_string_free (slaves_str, FALSE); @@ -1401,7 +1410,7 @@ print_team_info (NMDevice *device, g_ptr_array_add (out.output_data, arr); print_data_prepare_width (out.output_data); - print_data (&nmc->nmc_config, out_indices, NULL, 0, &out); + print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out); g_string_free (slaves_str, FALSE); @@ -1424,9 +1433,9 @@ show_device_info (NMDevice *device, NmCli *nmc) const char *base_hdr = _("Device details"); GPtrArray *fields_in_section = NULL; - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) + if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) fields_str = NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON; - else if (strcasecmp (nmc->required_fields, "all") == 0) { + else if (g_ascii_strcasecmp (nmc->required_fields, "all") == 0) { } else fields_str = nmc->required_fields; @@ -1456,9 +1465,13 @@ show_device_info (NMDevice *device, NmCli *nmc) for (i = 0; i < G_N_ELEMENTS (metagen_device_detail_general); i++) row[i].info = (const NMMetaAbstractInfo *) &metagen_device_detail_general[i]; - print_required_fields (&nmc->nmc_config, NMC_OF_FLAG_MAIN_HEADER_ONLY, - out_indices, header_name, - 0, row); + print_required_fields (&nmc->nmc_config, + &nmc->pager_data, + NMC_OF_FLAG_MAIN_HEADER_ONLY, + out_indices, + header_name, + 0, + row); } /* Loop through the required sections and print them. */ @@ -1537,10 +1550,9 @@ show_device_info (NMDevice *device, NmCli *nmc) if ((NM_IS_DEVICE_WIFI (device))) { NMAccessPoint *active_ap = NULL; const char *active_bssid = NULL; - GPtrArray *aps; /* section AP */ - if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[4]->name)) { + if (!g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[4]->name)) { NMC_OUTPUT_DATA_DEFINE_SCOPED (out); if (state == NM_DEVICE_STATE_ACTIVATED) { @@ -1555,6 +1567,7 @@ show_device_info (NMDevice *device, NmCli *nmc) g_ptr_array_add (out.output_data, arr); { + gs_unref_ptrarray GPtrArray *aps = NULL; APInfo info = { .nmc = nmc, .index = 1, @@ -1566,11 +1579,10 @@ show_device_info (NMDevice *device, NmCli *nmc) aps = sort_access_points (nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device))); g_ptr_array_foreach (aps, fill_output_access_point, &info); - g_ptr_array_free (aps, FALSE); } print_data_prepare_width (out.output_data); - print_data (&nmc->nmc_config, out_indices, NULL, 0, &out); + print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out); was_output = TRUE; } } @@ -1598,42 +1610,42 @@ show_device_info (NMDevice *device, NmCli *nmc) dhcp6 = nm_device_get_dhcp6_config (device); /* IP4 */ - if (cfg4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[8]->name)) + if (cfg4 && !g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[8]->name)) was_output = print_ip_config (cfg4, AF_INET, &nmc->nmc_config, section_fld); /* DHCP4 */ - if (dhcp4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[9]->name)) + if (dhcp4 && !g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[9]->name)) was_output = print_dhcp_config (dhcp4, AF_INET, &nmc->nmc_config, section_fld); /* IP6 */ - if (cfg6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[10]->name)) + if (cfg6 && !g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[10]->name)) was_output = print_ip_config (cfg6, AF_INET6, &nmc->nmc_config, section_fld); /* DHCP6 */ - if (dhcp6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[11]->name)) + if (dhcp6 && !g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[11]->name)) was_output = print_dhcp_config (dhcp6, AF_INET6, &nmc->nmc_config, section_fld); /* Bond specific information */ if (NM_IS_DEVICE_BOND (device)) { - if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[12]->name)) + if (!g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[12]->name)) was_output = print_bond_bridge_info (device, nmc, nmc_fields_dev_show_sections[12]->name, section_fld); } /* Team specific information */ if (NM_IS_DEVICE_TEAM (device)) { - if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[13]->name)) + if (!g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[13]->name)) was_output = print_team_info (device, nmc, nmc_fields_dev_show_sections[13]->name, section_fld); } /* Bridge specific information */ if (NM_IS_DEVICE_BRIDGE (device)) { - if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[14]->name)) + if (!g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[14]->name)) was_output = print_bond_bridge_info (device, nmc, nmc_fields_dev_show_sections[14]->name, section_fld); } /* VLAN-specific information */ if ((NM_IS_DEVICE_VLAN (device))) { - if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[15]->name)) { + if (!g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[15]->name)) { char * vlan_id_str = g_strdup_printf ("%u", nm_device_vlan_get_vlan_id (NM_DEVICE_VLAN (device))); NMDevice *parent = nm_device_vlan_get_parent (NM_DEVICE_VLAN (device)); NMC_OUTPUT_DATA_DEFINE_SCOPED (out); @@ -1651,14 +1663,14 @@ show_device_info (NMDevice *device, NmCli *nmc) g_ptr_array_add (out.output_data, arr); print_data_prepare_width (out.output_data); - print_data (&nmc->nmc_config, out_indices, NULL, 0, &out); + print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out); was_output = TRUE; } } if (NM_IS_DEVICE_BT (device)) { - if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[16]->name)) { + if (!g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[16]->name)) { NMC_OUTPUT_DATA_DEFINE_SCOPED (out); tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_dev_show_bluetooth; @@ -1673,7 +1685,7 @@ show_device_info (NMDevice *device, NmCli *nmc) g_ptr_array_add (out.output_data, arr); print_data_prepare_width (out.output_data); - print_data (&nmc->nmc_config, out_indices, NULL, 0, &out); + print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out); was_output = TRUE; } } @@ -1716,8 +1728,8 @@ nmc_device_state_to_color (NMDeviceState state) return NM_META_COLOR_DEVICE_UNKNOWN; } -static NMCResultCode -do_devices_status (NmCli *nmc, int argc, char **argv) +static void +do_devices_status (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { GError *error = NULL; gs_free NMDevice **devices = NULL; @@ -1726,16 +1738,17 @@ do_devices_status (NmCli *nmc, int argc, char **argv) next_arg (nmc, &argc, &argv, NULL); if (nmc->complete) - return nmc->return_value; + return; if (argc) { g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) + if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) fields_str = "DEVICE,TYPE,STATE,CONNECTION"; - else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) { + else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0) { } else fields_str = nmc->required_fields; @@ -1750,14 +1763,13 @@ do_devices_status (NmCli *nmc, int argc, char **argv) &error)) { g_string_printf (nmc->return_text, _("Error: 'device status': %s"), error->message); g_error_free (error); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } - - return NMC_RESULT_SUCCESS; } -static NMCResultCode -do_device_show (NmCli *nmc, int argc, char **argv) +static void +do_device_show (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { gs_free_error GError *error = NULL; @@ -1771,16 +1783,18 @@ do_device_show (NmCli *nmc, int argc, char **argv) device = get_device (nmc, &argc, &argv, &error); if (!device) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); - return error->code; + nmc->return_value = error->code; + return; } if (argc) { g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (nmc->complete) - return nmc->return_value; + return; show_device_info (device, nmc); } else { @@ -1800,8 +1814,6 @@ do_device_show (NmCli *nmc, int argc, char **argv) g_free (devices); } - - return nmc->return_value; } static gboolean @@ -2024,8 +2036,8 @@ connect_device_cb (GObject *client, GAsyncResult *result, gpointer user_data) g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc); } -static NMCResultCode -do_device_connect (NmCli *nmc, int argc, char **argv) +static void +do_device_connect (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMDevice *device = NULL; AddAndActivateInfo *info; @@ -2039,16 +2051,18 @@ do_device_connect (NmCli *nmc, int argc, char **argv) device = get_device (nmc, &argc, &argv, &error); if (!device) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); - return error->code; + nmc->return_value = error->code; + return; } if (*argv) { g_string_printf (nmc->return_text, _("Error: extra argument not allowed: '%s'."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (nmc->complete) - return nmc->return_value; + return; /* * Use nowait_flag instead of should_wait, because exiting has to be postponed @@ -2079,8 +2093,6 @@ do_device_connect (NmCli *nmc, int argc, char **argv) /* Start progress indication */ if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) progress_id = g_timeout_add (120, progress_cb, device); - - return nmc->return_value; } typedef struct { @@ -2194,8 +2206,8 @@ reapply_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) } } -static NMCResultCode -do_device_reapply (NmCli *nmc, int argc, char **argv) +static void +do_device_reapply (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMDevice *device; DeviceCbInfo *info = NULL; @@ -2209,16 +2221,18 @@ do_device_reapply (NmCli *nmc, int argc, char **argv) device = get_device (nmc, &argc, &argv, &error); if (!device) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); - return error->code; + nmc->return_value = error->code; + return; } if (argc) { g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (nmc->complete) - return nmc->return_value; + return; nmc->nowait_flag = (nmc->timeout == 0); nmc->should_wait++; @@ -2229,8 +2243,6 @@ do_device_reapply (NmCli *nmc, int argc, char **argv) /* Now reapply the connection to the device */ nm_device_reapply_async (device, NULL, 0, 0, NULL, reapply_device_cb, info); - - return nmc->return_value; } typedef struct { @@ -2276,6 +2288,8 @@ modify_get_applied_cb (GObject *object, gs_free_error GError *error = NULL; NMConnection *connection; guint64 version_id; + int argc; + const char *const*argv; connection = nm_device_get_applied_connection_finish (device, result, @@ -2292,7 +2306,10 @@ modify_get_applied_cb (GObject *object, return; } - if (!nmc_read_connection_properties (info->nmc, connection, &info->argc, &info->argv, &error)) { + argc = info->argc; + argv = (const char *const*) info->argv; + + if (!nmc_process_connection_properties (info->nmc, connection, &argc, &argv, TRUE, &error)) { g_string_assign (nmc->return_text, error->message); nmc->return_value = error->code; g_slice_free (ModifyInfo, info); @@ -2306,8 +2323,8 @@ modify_get_applied_cb (GObject *object, nm_device_reapply_async (device, connection, version_id, 0, NULL, modify_reapply_cb, info); } -static NMCResultCode -do_device_modify (NmCli *nmc, int argc, char **argv) +static void +do_device_modify (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMDevice *device = NULL; ModifyInfo *info = NULL; @@ -2317,7 +2334,8 @@ do_device_modify (NmCli *nmc, int argc, char **argv) device = get_device (nmc, &argc, &argv, &error); if (!device) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); - return error->code; + nmc->return_value = error->code; + return; } if (nmc->timeout == -1) @@ -2329,11 +2347,9 @@ do_device_modify (NmCli *nmc, int argc, char **argv) info = g_slice_new0 (ModifyInfo); info->nmc = nmc; info->argc = argc; - info->argv = argv; + info->argv = nm_utils_strv_dup ((char **) argv, argc, TRUE); nm_device_get_applied_connection_async (device, 0, NULL, modify_get_applied_cb, info); - - return nmc->return_value; } static void @@ -2373,8 +2389,8 @@ disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) } } -static NMCResultCode -do_devices_disconnect (NmCli *nmc, int argc, char **argv) +static void +do_devices_disconnect (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMDevice *device; DeviceCbInfo *info = NULL; @@ -2387,7 +2403,7 @@ do_devices_disconnect (NmCli *nmc, int argc, char **argv) next_arg (nmc, &argc, &argv, NULL); queue = get_device_list (nmc, argc, argv); if (!queue) - return nmc->return_value; + return; if (nmc->complete) goto out; queue = g_slist_reverse (queue); @@ -2418,7 +2434,6 @@ do_devices_disconnect (NmCli *nmc, int argc, char **argv) out: g_slist_free (queue); - return nmc->return_value; } static void @@ -2445,8 +2460,8 @@ delete_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) } } -static NMCResultCode -do_devices_delete (NmCli *nmc, int argc, char **argv) +static void +do_devices_delete (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMDevice *device; DeviceCbInfo *info = NULL; @@ -2459,7 +2474,7 @@ do_devices_delete (NmCli *nmc, int argc, char **argv) next_arg (nmc, &argc, &argv, NULL); queue = get_device_list (nmc, argc, argv); if (!queue) - return nmc->return_value; + return; if (nmc->complete) goto out; queue = g_slist_reverse (queue); @@ -2483,11 +2498,10 @@ do_devices_delete (NmCli *nmc, int argc, char **argv) out: g_slist_free (queue); - return nmc->return_value; } -static NMCResultCode -do_device_set (NmCli *nmc, int argc, char **argv) +static void +do_device_set (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { #define DEV_SET_AUTOCONNECT 0 #define DEV_SET_MANAGED 1 @@ -2509,12 +2523,14 @@ do_device_set (NmCli *nmc, int argc, char **argv) device = get_device (nmc, &argc, &argv, &error); if (!device) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); - return error->code; + nmc->return_value = error->code; + return; } if (!argc) { g_string_printf (nmc->return_text, _("Error: No property specified.")); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } i = 0; @@ -2529,14 +2545,16 @@ do_device_set (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (argc == 1 && nmc->complete) nmc_complete_bool (*argv); if (!nmc_string_to_bool (*argv, &flag, &error)) { g_string_printf (nmc->return_text, _("Error: 'managed': %s."), error->message); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } values[DEV_SET_MANAGED].idx = ++i; values[DEV_SET_MANAGED].value = flag; @@ -2546,26 +2564,29 @@ do_device_set (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (argc == 1 && nmc->complete) nmc_complete_bool (*argv); if (!nmc_string_to_bool (*argv, &flag, &error)) { g_string_printf (nmc->return_text, _("Error: 'autoconnect': %s."), error->message); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } values[DEV_SET_AUTOCONNECT].idx = ++i; values[DEV_SET_AUTOCONNECT].value = flag; } else { g_string_printf (nmc->return_text, _("Error: property '%s' is not known."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } } while (next_arg (nmc, &argc, &argv, NULL) == 0); if (nmc->complete) - return nmc->return_value; + return; /* when multiple properties are specified, set them in the order as they * are specified on the command line. */ @@ -2579,8 +2600,6 @@ do_device_set (NmCli *nmc, int argc, char **argv) nm_device_set_autoconnect (device, values[DEV_SET_AUTOCONNECT].value); if (values[DEV_SET_MANAGED].idx >= 0) nm_device_set_managed (device, values[DEV_SET_MANAGED].value); - - return nmc->return_value; } static void @@ -2645,11 +2664,11 @@ device_removed (NMClient *client, NMDevice *device, NmCli *nmc) device_unwatch (nmc, device); } -static NMCResultCode -do_devices_monitor (NmCli *nmc, int argc, char **argv) +static void +do_devices_monitor (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { if (nmc->complete) - return nmc->return_value; + return; next_arg (nmc, &argc, &argv, NULL); if (argc == 0) { @@ -2674,7 +2693,6 @@ do_devices_monitor (NmCli *nmc, int argc, char **argv) } g_signal_connect (nmc->client, NM_CLIENT_DEVICE_REMOVED, G_CALLBACK (device_removed), nmc); - return nmc->return_value; } /* @@ -2779,7 +2797,6 @@ show_access_point_info (NMDeviceWifi *wifi, NmCli *nmc, NmcOutputData *out) { NMAccessPoint *active_ap = NULL; const char *active_bssid = NULL; - GPtrArray *aps; NmcOutputField *arr; if (nm_device_get_state (NM_DEVICE (wifi)) == NM_DEVICE_STATE_ACTIVATED) { @@ -2792,6 +2809,7 @@ show_access_point_info (NMDeviceWifi *wifi, NmCli *nmc, NmcOutputData *out) g_ptr_array_add (out->output_data, arr); { + gs_unref_ptrarray GPtrArray *aps = NULL; APInfo info = { .nmc = nmc, .index = 1, @@ -2803,7 +2821,6 @@ show_access_point_info (NMDeviceWifi *wifi, NmCli *nmc, NmcOutputData *out) aps = sort_access_points (nm_device_wifi_get_access_points (wifi)); g_ptr_array_foreach (aps, fill_output_access_point, &info); - g_ptr_array_free (aps, TRUE); } print_data_prepare_width (out->output_data); @@ -2814,7 +2831,8 @@ wifi_print_aps (NMDeviceWifi *wifi, NmCli *nmc, GArray *_out_indices, const NMMetaAbstractInfo *const*tmpl, - const char *bssid_user) + const char *bssid_user, + gboolean *bssid_found) { NMAccessPoint *ap = NULL; const GPtrArray *aps; @@ -2838,14 +2856,13 @@ wifi_print_aps (NMDeviceWifi *wifi, /* Specific AP requested - list only that */ aps = nm_device_wifi_get_access_points (wifi); for (i = 0; i < aps->len; i++) { - char *bssid_up; NMAccessPoint *candidate_ap = g_ptr_array_index (aps, i); - const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap); - bssid_up = g_ascii_strup (bssid_user, -1); - if (!strcmp (bssid_up, candidate_bssid)) + if (nm_utils_hwaddr_matches (bssid_user, + -1, + nm_access_point_get_bssid (candidate_ap), + -1)) ap = candidate_ap; - g_free (bssid_up); } if (ap) { /* Add headers (field names) */ @@ -2863,25 +2880,38 @@ wifi_print_aps (NMDeviceWifi *wifi, fill_output_access_point (ap, info); print_data_prepare_width (out.output_data); - print_data (&nmc->nmc_config, out_indices, header_name, 0, &out); + print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, header_name, 0, &out); g_free (info); - nmc->return_value = NMC_RESULT_SUCCESS; + *bssid_found = TRUE; empty_line = TRUE; } } else { show_access_point_info (wifi, nmc, &out); - print_data (&nmc->nmc_config, out_indices, header_name, 0, &out); + print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, header_name, 0, &out); empty_line = TRUE; } } +static gint64 +_device_wifi_get_last_scan (NMDeviceWifi *wifi) +{ + gint64 timestamp; + + timestamp = nm_device_wifi_get_last_scan (wifi); + if (timestamp == -1) + return G_MININT64; + return timestamp; +} + typedef struct { NmCli *nmc; NMDevice **devices; const NMMetaAbstractInfo *const *tmpl; - const char *bssid_user; + char *bssid_user; GArray *out_indices; + gint64 rescan_cutoff_msec; + guint pending; } ScanInfo; typedef struct { @@ -2893,79 +2923,94 @@ typedef struct { } WifiListData; static void -wifi_list_finish (WifiListData *data) +wifi_list_finish (WifiListData *wifi_list_data, + gboolean force_finished) { - ScanInfo *info = data->scan_info; - NmCli *nmc = info->nmc; + ScanInfo *scan_info = wifi_list_data->scan_info; + NmCli *nmc = scan_info->nmc; + gboolean bssid_found = FALSE; guint i; - if (--info->nmc->should_wait == 0) { - for (i = 0; info->devices[i]; i++) { - wifi_print_aps (NM_DEVICE_WIFI (info->devices[i]), - info->nmc, - info->out_indices, - info->tmpl, - info->bssid_user); - } - if (nmc->return_value == NMC_RESULT_ERROR_NOT_FOUND) { - g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."), - data->scan_info->bssid_user); - } - g_main_loop_quit (loop); + if ( !force_finished + && scan_info->rescan_cutoff_msec > _device_wifi_get_last_scan (wifi_list_data->wifi)) { + /* wait longer... */ + return; + } + + nm_clear_g_signal_handler (wifi_list_data->wifi, &wifi_list_data->last_scan_id); + nm_clear_g_source (&wifi_list_data->timeout_id); + nm_clear_g_cancellable (&wifi_list_data->scan_cancellable); + nm_g_slice_free (wifi_list_data); + + if (--scan_info->pending > 0) + return; + + for (i = 0; scan_info->devices[i]; i++) { + wifi_print_aps (NM_DEVICE_WIFI (scan_info->devices[i]), + nmc, + scan_info->out_indices, + scan_info->tmpl, + scan_info->bssid_user, + &bssid_found); } - g_signal_handler_disconnect (data->wifi, data->last_scan_id); - nm_clear_g_source (&data->timeout_id); - nm_clear_g_cancellable (&data->scan_cancellable); - g_slice_free (WifiListData, data); - - if (info->nmc->should_wait == 0) { - for (i = 0; info->devices[i]; i++) - g_object_unref (info->devices[i]); - g_free (info->devices); - g_array_unref (info->out_indices); - g_free (info); + if ( scan_info->bssid_user + && !bssid_found) { + nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; + g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."), + scan_info->bssid_user); } + + for (i = 0; scan_info->devices[i]; i++) + g_object_unref (scan_info->devices[i]); + g_free (scan_info->devices); + g_array_unref (scan_info->out_indices); + g_free (scan_info->bssid_user); + nm_g_slice_free (scan_info); + + nmc->should_wait--; + g_main_loop_quit (loop); } static void wifi_last_scan_updated (GObject *gobject, GParamSpec *pspec, gpointer user_data) { - WifiListData *data = user_data; - - wifi_list_finish (data); + wifi_list_finish (user_data, FALSE); } static void wifi_list_rescan_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { NMDeviceWifi *wifi = NM_DEVICE_WIFI (source_object); - WifiListData *data = user_data; gs_free_error GError *error = NULL; + WifiListData *wifi_list_data; + gboolean force_finished; - if (!nm_device_wifi_request_scan_finish (wifi, res, &error)) { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; + nm_device_wifi_request_scan_finish (wifi, res, &error); + if (nm_utils_error_is_cancelled (error)) + return; - if (g_error_matches (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED)) { - /* This likely means that scanning is already in progress. There's - * a good chance we'll get updated results soon; wait for them. */ - return; - } + if (g_error_matches (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED)) { + /* This likely means that scanning is already in progress. There's + * a good chance we'll get updated results soon; wait for them. */ + force_finished = FALSE; + } else if (error) + force_finished = TRUE; + else + force_finished = FALSE; - /* Scanning could not be initiated for unknown reason, - * no point in waiting for results. */ - wifi_list_finish (data); - } + wifi_list_data = user_data; + g_clear_object (&wifi_list_data->scan_cancellable); + wifi_list_finish (wifi_list_data, force_finished); } static gboolean wifi_list_scan_timeout (gpointer user_data) { - WifiListData *data = user_data; - - wifi_list_finish (data); + WifiListData *wifi_list_data = user_data; + wifi_list_data->timeout_id = 0; + wifi_list_finish (user_data, TRUE); return G_SOURCE_REMOVE; } @@ -2989,8 +3034,8 @@ nmc_complete_bssid (NMClient *client, const char *ifname, const char *bssid_pref complete_aps (devices, ifname, bssid_prefix, NULL); } -static NMCResultCode -do_device_wifi_list (NmCli *nmc, int argc, char **argv) +static void +do_device_wifi_list (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { GError *error = NULL; NMDevice *device = NULL; @@ -3002,10 +3047,10 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) const NMMetaAbstractInfo *const*tmpl; gs_unref_array GArray *out_indices = NULL; int option; - guint64 rescan_cutoff; - NMDeviceWifi *wifi; + gint64 rescan_cutoff_msec; ScanInfo *scan_info = NULL; - WifiListData *data; + gboolean ifname_handled; + NMDevice *ifname_handled_candidate; guint i, j; devices = nmc_get_devices_sorted (nmc->client); @@ -3017,7 +3062,8 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } ifname = *argv; if (argc == 1 && nmc->complete) @@ -3029,20 +3075,20 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } bssid_user = *argv; if (argc == 1 && nmc->complete) complete_aps (devices, NULL, bssid_user, NULL); - /* We'll switch this to NMC_RESULT_SUCCESS if we find an access point. */ - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; break; case 4: /* --rescan */ argc--; argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } rescan = *argv; if (argc == 1 && nmc->complete) @@ -3054,9 +3100,12 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) } } - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) + if (nmc->complete) + return; + + if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) fields_str = NMC_FIELDS_DEV_WIFI_LIST_COMMON; - else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) { + else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0) { } else fields_str = nmc->required_fields; @@ -3066,101 +3115,134 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) if (error) { g_string_printf (nmc->return_text, _("Error: 'device wifi': %s"), error->message); g_error_free (error); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } - if (nmc->complete) - return nmc->return_value; - if (argc) { g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } - if (rescan == NULL || strcmp (rescan, "auto") == 0) { - rescan_cutoff = NM_MAX (nm_utils_get_timestamp_msec () - 30 * NM_UTILS_MSEC_PER_SECOND, 0); - } else if (strcmp (rescan, "no") == 0) { - rescan_cutoff = 0; - } else if (strcmp (rescan, "yes") == 0) { - rescan_cutoff = -1; - } else { + if (NM_IN_STRSET (rescan, NULL, "auto")) + rescan_cutoff_msec = nm_utils_get_timestamp_msec () - (30 * NM_UTILS_MSEC_PER_SEC); + else if (nm_streq (rescan, "no")) + rescan_cutoff_msec = G_MININT64; + else if (nm_streq (rescan, "yes")) + rescan_cutoff_msec = nm_utils_get_timestamp_msec (); + else { g_string_printf (nmc->return_text, _("Error: invalid rescan argument: '%s' not among [auto, no, yes]"), rescan); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } - if (ifname) { - device = find_wifi_device_by_iface (devices, ifname, NULL); - if (!device) { - g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname); - return NMC_RESULT_ERROR_NOT_FOUND; + ifname_handled = (ifname == NULL); + ifname_handled_candidate = NULL; + + j = 0; + for (i = 0; devices[i]; i++) { + const char *dev_iface; + + device = devices[i]; + dev_iface = nm_device_get_iface (device); + + if (ifname) { + if (!nm_streq0 (ifname, dev_iface)) + continue; + if (!NM_IS_DEVICE_WIFI (device)) { + if ( nm_device_get_device_type (device) == NM_DEVICE_TYPE_GENERIC + && nm_streq0 (nm_device_get_type_description (device), "wifi")) + ifname_handled_candidate = device; + else if (!ifname_handled_candidate) + ifname_handled_candidate = device; + continue; + } + ifname_handled = TRUE; + } else { + if (!NM_IS_DEVICE_WIFI (device)) + continue; } - if (NM_IS_DEVICE_WIFI (device)) { - devices[0] = device; - devices[1] = NULL; + devices[j++] = device; + } + devices[j] = NULL; + + if (!ifname_handled) { + if (!ifname_handled_candidate) { + g_string_printf (nmc->return_text, + _("Error: Device '%s' not found."), + ifname); + } else if ( nm_device_get_device_type (ifname_handled_candidate) == NM_DEVICE_TYPE_GENERIC + && nm_streq0 (nm_device_get_type_description (ifname_handled_candidate), "wifi")) { + g_string_printf (nmc->return_text, + _("Error: Device '%s' was not recognized as a Wi-Fi device, check NetworkManager Wi-Fi plugin."), + ifname); } else { - if ( nm_device_get_device_type (device) == NM_DEVICE_TYPE_GENERIC - && g_strcmp0 (nm_device_get_type_description (device), "wifi") == 0) { - g_string_printf (nmc->return_text, - _("Error: Device '%s' was not recognized as a Wi-Fi device, check NetworkManager Wi-Fi plugin."), - ifname); - } else { - g_string_printf (nmc->return_text, - _("Error: Device '%s' is not a Wi-Fi device."), - ifname); - } - return NMC_RESULT_ERROR_UNKNOWN; + g_string_printf (nmc->return_text, + _("Error: Device '%s' is not a Wi-Fi device."), + ifname); } + nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; + return; } - /* Filter out non-wifi devices */ - for (i = 0, j = 0; devices[i]; i++) { - if (NM_IS_DEVICE_WIFI (devices[i])) - devices[j++] = devices[i]; + if (!devices[0]) { + if (bssid_user) { + nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; + g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."), + bssid_user); + nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; + } + return; } - devices[j] = NULL; - /* Start a new scan for devices that need it */ - for (i = 0; devices[i]; i++) { - wifi = (NMDeviceWifi *) devices[i]; - g_object_ref (wifi); + scan_info = g_slice_new (ScanInfo); + *scan_info = (ScanInfo) { + .out_indices = g_array_ref (out_indices), + .tmpl = tmpl, + .bssid_user = g_strdup (bssid_user), + .nmc = nmc, + .rescan_cutoff_msec = rescan_cutoff_msec, + }; - if ( rescan_cutoff == 0 - || (rescan_cutoff > 0 && nm_device_wifi_get_last_scan (wifi) >= rescan_cutoff)) - continue; + for (i = 0; devices[i]; i++) + g_object_ref (devices[i]); - if (!scan_info) { - scan_info = g_new0 (ScanInfo, 1); - scan_info->out_indices = g_array_ref (out_indices); - scan_info->tmpl = tmpl; - scan_info->bssid_user = bssid_user; - scan_info->nmc = nmc; - } + for (i = 0; devices[i]; i++) { + NMDeviceWifi *wifi = NM_DEVICE_WIFI (devices[i]); + WifiListData *wifi_list_data; + int timeout_msec; - nmc->should_wait++; - data = g_slice_new0 (WifiListData); - data->wifi = wifi; - data->scan_info = scan_info; - data->last_scan_id = g_signal_connect (wifi, "notify::" NM_DEVICE_WIFI_LAST_SCAN, - G_CALLBACK (wifi_last_scan_updated), data); - data->scan_cancellable = g_cancellable_new (); - data->timeout_id = g_timeout_add_seconds (15, wifi_list_scan_timeout, data); - nm_device_wifi_request_scan_async (wifi, data->scan_cancellable, wifi_list_rescan_cb, data); - } + if (rescan_cutoff_msec <= _device_wifi_get_last_scan (wifi)) + timeout_msec = 0; + else + timeout_msec = 15000; + + wifi_list_data = g_slice_new (WifiListData); + *wifi_list_data = (WifiListData) { + .wifi = wifi, + .scan_info = scan_info, + .timeout_id = g_timeout_add (timeout_msec, + wifi_list_scan_timeout, + wifi_list_data), + }; - if (scan_info) { - scan_info->devices = g_steal_pointer (&devices); - } else { - /* Print results right away if no scan is pending */ - for (i = 0; devices[i]; i++) { - wifi_print_aps (NM_DEVICE_WIFI (devices[i]), - nmc, out_indices, - tmpl, bssid_user); - g_object_unref (devices[i]); + scan_info->pending++; + + if (timeout_msec > 0) { + wifi_list_data->last_scan_id = g_signal_connect (wifi, + "notify::" NM_DEVICE_WIFI_LAST_SCAN, + G_CALLBACK (wifi_last_scan_updated), + wifi_list_data), + wifi_list_data->scan_cancellable = g_cancellable_new (), + nm_device_wifi_request_scan_async (wifi, wifi_list_data->scan_cancellable, wifi_list_rescan_cb, wifi_list_data); } } - return nmc->return_value; + scan_info->devices = g_steal_pointer (&devices); + + nmc->should_wait++; } static void @@ -3224,8 +3306,8 @@ save_and_activate_connection (NmCli *nmc, } } -static NMCResultCode -do_device_wifi_connect (NmCli *nmc, int argc, char **argv) +static void +do_device_wifi_connect (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMDevice *device = NULL; NMAccessPoint *ap = NULL; @@ -3561,8 +3643,8 @@ do_device_wifi_connect (NmCli *nmc, int argc, char **argv) /* Set password for WEP or WPA-PSK. */ 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) { + || (ap_wpa_flags != NM_802_11_AP_SEC_NONE && !(ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_OWE)) + || (ap_rsn_flags != NM_802_11_AP_SEC_NONE && !(ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_OWE))) { const char *con_password = NULL; NMSettingWirelessSecurity *s_wsec = NULL; @@ -3634,9 +3716,7 @@ finish: if (bssid2_arr) g_byte_array_free (bssid2_arr, TRUE); g_free (ssid_ask); - g_free (passwd_ask); - - return nmc->return_value; + nm_free_secret (passwd_ask); } static GBytes * @@ -3865,8 +3945,8 @@ create_hotspot_conn (const GPtrArray *connections, return connection; } -static NMCResultCode -do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) +static void +do_device_wifi_hotspot (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { const char *ifname = NULL; const char *con_name = NULL; @@ -3903,7 +3983,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } ifname = *argv; if (argc == 1 && nmc->complete) @@ -3913,7 +3994,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } con_name = *argv; } else if (strcmp (*argv, "ssid") == 0) { @@ -3921,11 +4003,13 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (strlen (*argv) > 32) { g_string_printf (nmc->return_text, _("Error: ssid is too long.")); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } ssid_bytes = g_bytes_new (*argv, strlen (*argv)); } else if (strcmp (*argv, "band") == 0) { @@ -3933,7 +4017,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } band = *argv; if (argc == 1 && nmc->complete) @@ -3941,14 +4026,16 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) if (strcmp (band, "a") && strcmp (band, "bg")) { g_string_printf (nmc->return_text, _("Error: band argument value '%s' is invalid; use 'a' or 'bg'."), band); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } } else if (strcmp (*argv, "channel") == 0) { argc--; argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } channel = *argv; } else if (strcmp (*argv, "password") == 0) { @@ -3956,7 +4043,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } password = *argv; /* --show-password is deprecated in favour of global --show-secrets option */ @@ -3965,7 +4053,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) show_password = TRUE; } else { g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } next_arg (nmc, &argc, &argv, NULL); @@ -3973,7 +4062,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) show_password = nmc->nmc_config.show_secrets || show_password; if (nmc->complete) - return nmc->return_value; + return; /* Verify band and channel parameters */ if (!channel) { @@ -3987,13 +4076,15 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) if (!band) { g_string_printf (nmc->return_text, _("Error: channel requires band too.")); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if ( !nmc_string_to_uint (channel, TRUE, 1, 5825, &value) || !nm_utils_wifi_is_channel_valid (value, band)) { g_string_printf (nmc->return_text, _("Error: channel '%s' not valid for band '%s'."), channel, band); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } channel_int = value; @@ -4006,7 +4097,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), ifname); else g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found.")); - return NMC_RESULT_ERROR_UNKNOWN; + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return; } /* Check device supported mode */ @@ -4018,7 +4110,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) else { g_string_printf (nmc->return_text, _("Error: Device '%s' supports neither AP nor Ad-Hoc mode."), nm_device_get_iface (device)); - return NMC_RESULT_ERROR_UNKNOWN; + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return; } connections = nm_client_get_connections (nmc->client); @@ -4034,13 +4127,14 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) if (password || !NM_IS_REMOTE_CONNECTION (connection)) { s_wsec = nm_connection_get_setting_wireless_security (connection); - g_return_val_if_fail (s_wsec, NMC_RESULT_ERROR_UNKNOWN); + g_return_if_fail (s_wsec); if (!set_wireless_security_for_hotspot (s_wsec, wifi_mode, caps, password, show_password, &error)) { g_object_unref (connection); g_string_printf (nmc->return_text, _("Error: Invalid 'password': %s."), error->message); g_clear_error (&error); - return NMC_RESULT_ERROR_UNKNOWN; + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return; } } @@ -4049,8 +4143,6 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) nmc->should_wait++; save_and_activate_connection (nmc, device, connection, TRUE, NULL); - - return nmc->return_value; } static void @@ -4068,16 +4160,15 @@ request_rescan_cb (GObject *object, GAsyncResult *result, gpointer user_data) quit (); } -static NMCResultCode -do_device_wifi_rescan (NmCli *nmc, int argc, char **argv) +static void +do_device_wifi_rescan (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMDevice *device; const char *ifname = NULL; - GPtrArray *ssids; + gs_unref_ptrarray GPtrArray *ssids = NULL; gs_free NMDevice **devices = NULL; GVariantBuilder builder, array_builder; GVariant *options; - const char *ssid; int i; ssids = g_ptr_array_new (); @@ -4093,14 +4184,14 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv) if (ifname) { g_string_printf (nmc->return_text, _("Error: '%s' cannot repeat."), *(argv-1)); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + return; } argc--; argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + return; } ifname = *argv; if (argc == 1 && nmc->complete) @@ -4111,20 +4202,20 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv) if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + return; } - g_ptr_array_add (ssids, *argv); + g_ptr_array_add (ssids, (gpointer) *argv); } else if (!nmc->complete) { g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto finish; + return; } next_arg (nmc, &argc, &argv, NULL); } if (nmc->complete) - goto finish; + return; /* Find Wi-Fi device to scan on. When no ifname is provided, the first Wi-Fi is used. */ device = find_wifi_device_by_iface (devices, ifname, NULL); @@ -4135,7 +4226,7 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv) else g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found.")); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto finish; + return; } if (ssids->len) { @@ -4143,7 +4234,8 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv) g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aay")); for (i = 0; i < ssids->len; i++) { - ssid = g_ptr_array_index (ssids, i); + const char *ssid = g_ptr_array_index (ssids, i); + g_variant_builder_add (&array_builder, "@ay", g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, ssid, strlen (ssid), 1)); } @@ -4158,9 +4250,6 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv) NULL, request_rescan_cb, nmc); nmc->should_wait++; -finish: - g_ptr_array_free (ssids, FALSE); - return nmc->return_value; } static void @@ -4234,6 +4323,9 @@ print_wifi_connection (const NmcConfig *nmc_config, NMConnection *connection) || strcmp (key_mgmt, "sae") == 0) { type = "WPA"; g_print ("%s: WPA\n", _("Security")); + } else if ( strcmp (key_mgmt, "owe") == 0) { + type = "nopass"; + g_print ("%s: OWE\n", _("Security")); } if (psk) @@ -4296,8 +4388,8 @@ wifi_show_device (const NmcConfig *nmc_config, NMDevice *device, GError **error) return TRUE; } -static NMCResultCode -do_device_wifi_show_password (NmCli *nmc, int argc, char **argv) +static void +do_device_wifi_show_password (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { const char *ifname = NULL; gs_free NMDevice **devices = NULL; @@ -4317,7 +4409,8 @@ do_device_wifi_show_password (NmCli *nmc, int argc, char **argv) g_string_printf (nmc->return_text, _("Error: '%s' cannot repeat."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } argc--; argv++; @@ -4325,7 +4418,8 @@ do_device_wifi_show_password (NmCli *nmc, int argc, char **argv) g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } ifname = *argv; if (argc == 1 && nmc->complete) @@ -4334,14 +4428,15 @@ do_device_wifi_show_password (NmCli *nmc, int argc, char **argv) g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } next_arg (nmc, &argc, &argv, NULL); } if (nmc->complete) - return nmc->return_value; + return; for (i = 0; devices[i]; i++) { if (ifname && g_strcmp0 (nm_device_get_iface (devices[i]), ifname) != 0) @@ -4353,7 +4448,8 @@ do_device_wifi_show_password (NmCli *nmc, int argc, char **argv) if (ifname) { g_string_printf (nmc->return_text, _("%s"), error->message); - return NMC_RESULT_ERROR_UNKNOWN; + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return; } g_clear_error (&error); } @@ -4365,10 +4461,9 @@ do_device_wifi_show_password (NmCli *nmc, int argc, char **argv) if (!found) { g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found.")); - return NMC_RESULT_ERROR_UNKNOWN; + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + return; } - - return nmc->return_value; } static NMCCommand device_wifi_cmds[] = { @@ -4380,13 +4475,11 @@ static NMCCommand device_wifi_cmds[] = { { NULL, do_device_wifi_list, NULL, TRUE, TRUE }, }; -static NMCResultCode -do_device_wifi (NmCli *nmc, int argc, char **argv) +static void +do_device_wifi (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { next_arg (nmc, &argc, &argv, NULL); nmc_do_cmd (nmc, device_wifi_cmds, *argv, argc, argv); - - return nmc->return_value; } static int @@ -4469,13 +4562,13 @@ show_device_lldp_list (NMDevice *device, NmCli *nmc, const char *fields_str, int } print_data_prepare_width (out.output_data); - print_data (&nmc->nmc_config, out_indices, header_name, 0, &out); + print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, header_name, 0, &out); return neighbors->len; } -static NMCResultCode -do_device_lldp_list (NmCli *nmc, int argc, char **argv) +static void +do_device_lldp_list (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMDevice *device = NULL; gs_free_error GError *error = NULL; @@ -4493,25 +4586,28 @@ do_device_lldp_list (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } device = get_device (nmc, &argc, &argv, &error); if (!device) { g_string_printf (nmc->return_text, _("Error: %s."), error->message); - return error->code; + nmc->return_value = error->code; + return; } } else { g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } next_arg (nmc, &argc, &argv, NULL); } - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) + if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) fields_str = NMC_FIELDS_DEV_LLDP_LIST_COMMON; - else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) { + else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0) { } else fields_str = nmc->required_fields; @@ -4519,25 +4615,22 @@ do_device_lldp_list (NmCli *nmc, int argc, char **argv) if (error) { g_string_printf (nmc->return_text, _("Error: 'device lldp list': %s"), error->message); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (nmc->complete) - return nmc->return_value; + return; if (device) { show_device_lldp_list (device, nmc, fields_str, &counter); } else { - NMDevice **devices = nmc_get_devices_sorted (nmc->client); - int i; + gs_free NMDevice **devices = nmc_get_devices_sorted (nmc->client); + guint i; for (i = 0; devices[i]; i++) show_device_lldp_list (devices[i], nmc, fields_str, &counter); - - g_free (devices); } - - return nmc->return_value; } static NMCCommand device_lldp_cmds[] = { @@ -4545,16 +4638,14 @@ static NMCCommand device_lldp_cmds[] = { { NULL, do_device_lldp_list, NULL, TRUE, TRUE }, }; -static NMCResultCode -do_device_lldp (NmCli *nmc, int argc, char **argv) +static void +do_device_lldp (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { if (!nmc->mode_specified) nmc->nmc_config_mutable.multiline_output = TRUE; /* multiline mode is default for 'device lldp' */ next_arg (nmc, &argc, &argv, NULL); nmc_do_cmd (nmc, device_lldp_cmds, *argv, argc, argv); - - return nmc->return_value; } static gboolean @@ -4599,38 +4690,35 @@ nmcli_device_tab_completion (const char *text, int start, int end) return match_array; } -static const NMCCommand device_cmds[] = { - { "status", do_devices_status, usage_device_status, TRUE, TRUE }, - { "show", do_device_show, usage_device_show, TRUE, TRUE }, - { "connect", do_device_connect, usage_device_connect, TRUE, TRUE }, - { "reapply", do_device_reapply, usage_device_reapply, TRUE, TRUE }, - { "disconnect", do_devices_disconnect, usage_device_disconnect, TRUE, TRUE }, - { "delete", do_devices_delete, usage_device_delete, TRUE, TRUE }, - { "set", do_device_set, usage_device_set, TRUE, TRUE }, - { "monitor", do_devices_monitor, usage_device_monitor, TRUE, TRUE }, - { "wifi", do_device_wifi, usage_device_wifi, FALSE, FALSE }, - { "lldp", do_device_lldp, usage_device_lldp, FALSE, FALSE }, - { "modify", do_device_modify, usage_device_modify, TRUE, TRUE }, - { NULL, do_devices_status, usage, TRUE, TRUE }, -}; - -NMCResultCode -do_devices (NmCli *nmc, int argc, char **argv) +void +nmc_command_func_device (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { + static const NMCCommand cmds[] = { + { "status", do_devices_status, usage_device_status, TRUE, TRUE }, + { "show", do_device_show, usage_device_show, TRUE, TRUE }, + { "connect", do_device_connect, usage_device_connect, TRUE, TRUE }, + { "reapply", do_device_reapply, usage_device_reapply, TRUE, TRUE }, + { "disconnect", do_devices_disconnect, usage_device_disconnect, TRUE, TRUE }, + { "delete", do_devices_delete, usage_device_delete, TRUE, TRUE }, + { "set", do_device_set, usage_device_set, TRUE, TRUE }, + { "monitor", do_devices_monitor, usage_device_monitor, TRUE, TRUE }, + { "wifi", do_device_wifi, usage_device_wifi, FALSE, FALSE }, + { "lldp", do_device_lldp, usage_device_lldp, FALSE, FALSE }, + { "modify", do_device_modify, usage_device_modify, TRUE, TRUE }, + { NULL, do_devices_status, usage, TRUE, TRUE }, + }; + next_arg (nmc, &argc, &argv, NULL); - /* Register polkit agent */ nmc_start_polkit_agent_start_try (nmc); rl_attempted_completion_function = (rl_completion_func_t *) nmcli_device_tab_completion; - nmc_do_cmd (nmc, device_cmds, *argv, argc, argv); - - return nmc->return_value; + nmc_do_cmd (nmc, cmds, *argv, argc, argv); } void monitor_devices (NmCli *nmc) { - do_devices_monitor (nmc, 0, NULL); + do_devices_monitor (NULL, nmc, 0, NULL); } diff --git a/clients/cli/devices.h b/clients/cli/devices.h index 055d56e7..8b7aa901 100644 --- a/clients/cli/devices.h +++ b/clients/cli/devices.h @@ -8,8 +8,6 @@ #include "nmcli.h" -NMCResultCode do_devices (NmCli *nmc, int argc, char **argv); - void nmc_complete_device (NMClient *client, const char *prefix, gboolean wifi_only); void nmc_complete_bssid (NMClient *client, const char *ifname, const char *bssid_prefix); diff --git a/clients/cli/general.c b/clients/cli/general.c index 123cc5b4..747203bb 100644 --- a/clients/cli/general.c +++ b/clients/cli/general.c @@ -5,8 +5,6 @@ #include "nm-default.h" -#include "general.h" - #include <stdlib.h> #include "nm-libnm-core-intern/nm-common-macros.h" @@ -22,7 +20,14 @@ /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (nm_state_to_string, NMState, +static void permission_changed (GObject *gobject, + GParamSpec *pspec, + NmCli *nmc); + +/*****************************************************************************/ + +static +NM_UTILS_LOOKUP_STR_DEFINE (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")), @@ -77,47 +82,12 @@ connectivity_to_color (NMConnectivityState connectivity) static const char * permission_to_string (NMClientPermission perm) { - switch (perm) { - case NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK: - return NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK; - case NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI: - return NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI; - case NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN: - return NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN; - case NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX: - return NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX; - case NM_CLIENT_PERMISSION_SLEEP_WAKE: - return NM_AUTH_PERMISSION_SLEEP_WAKE; - case NM_CLIENT_PERMISSION_NETWORK_CONTROL: - return NM_AUTH_PERMISSION_NETWORK_CONTROL; - case NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED: - return NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED; - case NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN: - return NM_AUTH_PERMISSION_WIFI_SHARE_OPEN; - case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM: - return NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM; - case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN: - return NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; - case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME: - return NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME; - case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS: - return NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS; - case NM_CLIENT_PERMISSION_RELOAD: - return NM_AUTH_PERMISSION_RELOAD; - case NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK: - return NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK; - case NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS: - 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"); - } + return nm_auth_permission_to_string (perm) + ?: _("unknown"); } -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (permission_result_to_string, NMClientPermissionResult, +static +NM_UTILS_LOOKUP_STR_DEFINE (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")), @@ -125,7 +95,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (permission_result_to_string, NMClientPermissi NM_UTILS_LOOKUP_ITEM_IGNORE (NM_CLIENT_PERMISSION_RESULT_UNKNOWN), ); -_NM_UTILS_LOOKUP_DEFINE (static, permission_result_to_color, NMClientPermissionResult, NMMetaColor, +static +NM_UTILS_LOOKUP_DEFINE (permission_result_to_color, NMClientPermissionResult, NMMetaColor, NM_UTILS_LOOKUP_DEFAULT (NM_META_COLOR_PERMISSION_UNKNOWN), NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_YES, NM_META_COLOR_PERMISSION_YES), NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_NO, NM_META_COLOR_PERMISSION_NO), @@ -497,9 +468,9 @@ show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_fl const char *fields_all = print_flds ?: NMC_FIELDS_NM_STATUS_ALL; const char *fields_common = print_flds ?: NMC_FIELDS_NM_STATUS_COMMON; - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) + if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) fields_str = fields_common; - else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) + else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0) fields_str = fields_all; else fields_str = nmc->required_fields; @@ -518,15 +489,14 @@ show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_fl return TRUE; } -static NMCResultCode -do_general_status (NmCli *nmc, int argc, char **argv) +static void +do_general_status (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { next_arg (nmc, &argc, &argv, NULL); if (nmc->complete) - return nmc->return_value; + return; show_nm_status (nmc, NULL, NULL); - return nmc->return_value; } static gboolean @@ -534,32 +504,56 @@ timeout_cb (gpointer user_data) { NmCli *nmc = (NmCli *) user_data; + g_signal_handlers_disconnect_by_func (nmc->client, + G_CALLBACK (permission_changed), + nmc); + g_string_printf (nmc->return_text, _("Error: Timeout %d sec expired."), nmc->timeout); nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED; quit (); return FALSE; } -static int +static void print_permissions (void *user_data) { NmCli *nmc = user_data; gs_free_error GError *error = NULL; const char *fields_str = NULL; - NMClientPermission perm; - guint i; - gpointer permissions[NM_CLIENT_PERMISSION_LAST + 1]; + gpointer permissions[G_N_ELEMENTS (nm_auth_permission_sorted) + 1]; + gboolean is_running; + int i; + + is_running = nm_client_get_nm_running (nmc->client); + + if ( is_running + && nm_client_get_permissions_state (nmc->client) != NM_TERNARY_TRUE) { + /* wait longer. Permissions are not up to date. */ + return; + } + + g_signal_handlers_disconnect_by_func (nmc->client, + G_CALLBACK (permission_changed), + nmc); - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) { - } else if (strcasecmp (nmc->required_fields, "all") == 0) { + if (!is_running) { + /* NetworkManager quit while we were waiting. */ + g_string_printf (nmc->return_text, _("NetworkManager is not running.")); + nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING; + quit (); + return; + } + + if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) { + } else if (g_ascii_strcasecmp (nmc->required_fields, "all") == 0) { } else fields_str = nmc->required_fields; - for (i = 0, perm = NM_CLIENT_PERMISSION_NONE + 1; perm <= NM_CLIENT_PERMISSION_LAST; perm++) - permissions[i++] = GINT_TO_POINTER (perm); - permissions[i++] = NULL; + for (i = 0; i < (int) G_N_ELEMENTS (nm_auth_permission_sorted); i++) + permissions[i] = GINT_TO_POINTER (nm_auth_permission_sorted[i]); + permissions[i] = NULL; - nm_cli_spawn_pager (nmc); + nm_cli_spawn_pager (&nmc->nmc_config, &nmc->pager_data); if (!nmc_print (&nmc->nmc_config, permissions, @@ -573,64 +567,48 @@ print_permissions (void *user_data) } quit (); - return G_SOURCE_REMOVE; -} - -static gboolean -got_permissions (NmCli *nmc) -{ - NMClientPermission perm; - - /* The server returns all the permissions at once, so if at least one is there - * we already received the reply. */ - for (perm = NM_CLIENT_PERMISSION_NONE + 1; perm <= NM_CLIENT_PERMISSION_LAST; perm++) { - if (nm_client_get_permission_result (nmc->client, perm) != NM_CLIENT_PERMISSION_RESULT_UNKNOWN) - return TRUE; - } - - return FALSE; } static void -permission_changed (NMClient *client, - NMClientPermission permission, - NMClientPermissionResult result, +permission_changed (GObject *gobject, + GParamSpec *pspec, NmCli *nmc) { - if (got_permissions (nmc)) { - /* Defer the printing, so that we have a chance to process the other - * permission-changed signals. */ - g_signal_handlers_disconnect_by_func (nmc->client, - G_CALLBACK (permission_changed), - nmc); - g_idle_remove_by_data (nmc); - g_idle_add (print_permissions, nmc); - } + if (NM_IN_STRSET (pspec->name, NM_CLIENT_NM_RUNNING, + NM_CLIENT_PERMISSIONS_STATE)) + print_permissions (nmc); } static gboolean show_nm_permissions (NmCli *nmc) { - /* The permissions are available now, just print them. */ - if (got_permissions (nmc)) { - print_permissions (nmc); - return TRUE; - } + NMClientInstanceFlags instance_flags; + + instance_flags = nm_client_get_instance_flags (nmc->client); + instance_flags &= ~NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS; + + g_object_set (nmc->client, + NM_CLIENT_INSTANCE_FLAGS, (guint) instance_flags, + NULL); - /* The client didn't get the permissions reply yet. Subscribe to changes. */ - g_signal_connect (nmc->client, NM_CLIENT_PERMISSION_CHANGED, - G_CALLBACK (permission_changed), nmc); + g_signal_connect (nmc->client, + "notify", + G_CALLBACK (permission_changed), + nmc); if (nmc->timeout == -1) nmc->timeout = 10; g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc); nmc->should_wait++; + + print_permissions (nmc); + return TRUE; } -static NMCResultCode -do_general_reload (NmCli *nmc, int argc, char **argv) +static void +do_general_reload (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { gs_unref_variant GVariant *result = NULL; gs_free_error GError *error = NULL; @@ -643,7 +621,7 @@ do_general_reload (NmCli *nmc, int argc, char **argv) if (nmc->complete) { if (argc == 0) - return nmc->return_value; + return; if (argc == 1) { values = nm_utils_enum_get_values (nm_manager_reload_flags_get_type (), @@ -651,7 +629,7 @@ do_general_reload (NmCli *nmc, int argc, char **argv) NM_MANAGER_RELOAD_FLAG_ALL); nmc_complete_strv (*argv, -1, values); } - return nmc->return_value; + return; } if (argc > 0) { @@ -664,7 +642,8 @@ do_general_reload (NmCli *nmc, int argc, char **argv) _("Error: invalid reload flag '%s'. Allowed flags are: %s"), err_token, joined); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } argc--; argv++; @@ -672,7 +651,8 @@ do_general_reload (NmCli *nmc, int argc, char **argv) if (argc > 0) { g_string_printf (nmc->return_text, _("Error: extra argument '%s'"), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } result = nmc_dbus_call_sync (nmc, @@ -687,21 +667,18 @@ do_general_reload (NmCli *nmc, int argc, char **argv) g_string_printf (nmc->return_text, _("Error: failed to reload: %s"), nmc_error_get_simple_message (error)); - return NMC_RESULT_ERROR_UNKNOWN; + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; } - - return nmc->return_value; } -static NMCResultCode -do_general_permissions (NmCli *nmc, int argc, char **argv) +static void +do_general_permissions (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { next_arg (nmc, &argc, &argv, NULL); if (nmc->complete) - return nmc->return_value; + return; show_nm_permissions (nmc); - return nmc->return_value; } static void @@ -716,8 +693,8 @@ show_general_logging (NmCli *nmc) .domains = &domains_cache, }; - if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) { - } else if (strcasecmp (nmc->required_fields, "all") == 0) { + if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) { + } else if (g_ascii_strcasecmp (nmc->required_fields, "all") == 0) { } else fields_str = nmc->required_fields; @@ -750,15 +727,30 @@ nmc_complete_strings_nocase (const char *prefix, ...) va_end (args); } -static NMCResultCode -do_general_logging (NmCli *nmc, int argc, char **argv) +static void +_set_logging_cb (GObject *object, GAsyncResult *result, gpointer user_data) { + NmCli *nmc = user_data; + gs_unref_variant GVariant *res = NULL; gs_free_error GError *error = NULL; + res = nm_client_dbus_call_finish (NM_CLIENT (object), result, &error); + if (!res) { + g_dbus_error_strip_remote_error (error); + g_string_printf (nmc->return_text, _("Error: failed to set logging: %s"), + nmc_error_get_simple_message (error)); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + } + quit (); +} + +static void +do_general_logging (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) +{ next_arg (nmc, &argc, &argv, NULL); if (argc == 0) { if (nmc->complete) - return nmc->return_value; + return; show_general_logging (nmc); } else { @@ -775,7 +767,8 @@ do_general_logging (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (argc == 1 && nmc->complete) { nmc_complete_strings_nocase (*argv, "TRACE", "DEBUG", "INFO", "WARN", @@ -787,7 +780,8 @@ do_general_logging (NmCli *nmc, int argc, char **argv) argv++; if (!argc) { g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1)); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } if (argc == 1 && nmc->complete) { nmc_complete_strings_nocase (*argv, "PLATFORM", "RFKILL", "ETHER", "WIFI", "BT", @@ -801,93 +795,90 @@ do_general_logging (NmCli *nmc, int argc, char **argv) domains = *argv; } else { g_string_printf (nmc->return_text, _("Error: property '%s' is not known."), *argv); - return NMC_RESULT_ERROR_USER_INPUT; + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; } } while (next_arg (nmc, &argc, &argv, NULL) == 0); if (nmc->complete) - return nmc->return_value; + return; - nm_client_set_logging (nmc->client, level, domains, &error); - if (error) { - g_string_printf (nmc->return_text, _("Error: failed to set logging: %s"), - nmc_error_get_simple_message (error)); - return NMC_RESULT_ERROR_UNKNOWN; - } + nmc->should_wait++; + nm_client_dbus_call (nmc->client, + NM_DBUS_PATH, + NM_DBUS_INTERFACE, + "SetLogging", + g_variant_new ("(ss)", + level ?: "", + domains ?: ""), + G_VARIANT_TYPE ("()"), + -1, + NULL, + _set_logging_cb, + nmc); } - - return nmc->return_value; } static void save_hostname_cb (GObject *object, GAsyncResult *result, gpointer user_data) { - NmCli *nmc = (NmCli *) user_data; - GError *error = NULL; + NmCli *nmc = user_data; + gs_free_error GError *error = NULL; nm_client_save_hostname_finish (NM_CLIENT (object), result, &error); if (error) { g_string_printf (nmc->return_text, _("Error: failed to set hostname: %s"), error->message); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - g_error_free (error); } + quit (); } -static NMCResultCode -do_general_hostname (NmCli *nmc, int argc, char **argv) +static void +do_general_hostname (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { + const char *hostname; + next_arg (nmc, &argc, &argv, NULL); if (nmc->complete) - return nmc->return_value; + return; if (argc == 0) { /* no arguments -> get hostname */ - char *hostname = NULL; - - g_object_get (nmc->client, NM_CLIENT_HOSTNAME, &hostname, NULL); - if (hostname) - g_print ("%s\n", hostname); - g_free (hostname); - } else { - /* hostname provided -> set it */ - const char *hostname = *argv; - - if (next_arg (nmc, &argc, &argv, NULL) == 0) - g_print ("Warning: ignoring extra garbage after '%s' hostname\n", hostname); + gs_free char *s = NULL; - nmc->should_wait++; - nm_client_save_hostname_async (nmc->client, hostname, NULL, save_hostname_cb, nmc); + g_object_get (nmc->client, NM_CLIENT_HOSTNAME, &s, NULL); + if (s) + g_print ("%s\n", s); + return; } - return nmc->return_value; + hostname = *argv; + if (next_arg (nmc, &argc, &argv, NULL) == 0) + g_print ("Warning: ignoring extra garbage after '%s' hostname\n", hostname); + nmc->should_wait++; + nm_client_save_hostname_async (nmc->client, hostname, NULL, save_hostname_cb, nmc); } -static const NMCCommand general_cmds[] = { - { "status", do_general_status, usage_general_status, TRUE, TRUE }, - { "hostname", do_general_hostname, usage_general_hostname, TRUE, TRUE }, - { "permissions", do_general_permissions, usage_general_permissions, TRUE, TRUE }, - { "logging", do_general_logging, usage_general_logging, TRUE, TRUE }, - { "reload", do_general_reload, usage_general_reload, FALSE, FALSE }, - { NULL, do_general_status, usage_general, TRUE, TRUE }, -}; - -/* - * Entry point function for general operations 'nmcli general' - */ -NMCResultCode -do_general (NmCli *nmc, int argc, char **argv) +void +nmc_command_func_general (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { + static const NMCCommand cmds[] = { + { "status", do_general_status, usage_general_status, TRUE, TRUE }, + { "hostname", do_general_hostname, usage_general_hostname, TRUE, TRUE }, + { "permissions", do_general_permissions, usage_general_permissions, TRUE, TRUE }, + { "logging", do_general_logging, usage_general_logging, TRUE, TRUE }, + { "reload", do_general_reload, usage_general_reload, FALSE, FALSE }, + { NULL, do_general_status, usage_general, TRUE, TRUE }, + }; + next_arg (nmc, &argc, &argv, NULL); - /* Register polkit agent */ nmc_start_polkit_agent_start_try (nmc); - nmc_do_cmd (nmc, general_cmds, *argv, argc, argv); - - return nmc->return_value; + nmc_do_cmd (nmc, cmds, *argv, argc, argv); } static gboolean @@ -896,7 +887,7 @@ nmc_switch_show (NmCli *nmc, const char *switch_name, const char *header) g_return_val_if_fail (nmc != NULL, FALSE); g_return_val_if_fail (switch_name != NULL, FALSE); - if (nmc->required_fields && strcasecmp (nmc->required_fields, switch_name) != 0) { + if (nmc->required_fields && g_ascii_strcasecmp (nmc->required_fields, switch_name) != 0) { g_string_printf (nmc->return_text, _("Error: '--fields' value '%s' is not valid here (allowed field: %s)"), nmc->required_fields, switch_name); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; @@ -930,42 +921,62 @@ nmc_switch_parse_on_off (NmCli *nmc, const char *arg1, const char *arg2, gboolea return TRUE; } -static NMCResultCode -do_networking_on_off (NmCli *nmc, int argc, char **argv, gboolean enable) +static void +_do_networking_on_off_cb (GObject *object, GAsyncResult *result, gpointer user_data) { - if (nmc->complete) - return nmc->return_value; - - /* Register polkit agent */ - nmc_start_polkit_agent_start_try (nmc); - - nm_client_networking_set_enabled (nmc->client, enable, NULL); + NmCli *nmc = user_data; + gs_unref_variant GVariant *ret = NULL; + gs_free_error GError *error = NULL; - return nmc->return_value; + ret = nm_client_dbus_call_finish (NM_CLIENT (object), result, &error); + if (!ret) { + if (g_error_matches (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED)) { + /* This is fine. Be quiet about it. */ + } else { + g_dbus_error_strip_remote_error (error); + g_string_printf (nmc->return_text, _("Error: failed to set networking: %s"), + nmc_error_get_simple_message (error)); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + } + } + quit (); } -static NMCResultCode -do_networking_on (NmCli *nmc, int argc, char **argv) +static void +do_networking_on_off (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { - next_arg (nmc, &argc, &argv, NULL); - return do_networking_on_off (nmc, argc, argv, TRUE); -} + gboolean enable = nm_streq (cmd->cmd, "on"); -static NMCResultCode -do_networking_off (NmCli *nmc, int argc, char **argv) -{ next_arg (nmc, &argc, &argv, NULL); - return do_networking_on_off (nmc, argc, argv, FALSE); + + if (nmc->complete) + return; + + nmc_start_polkit_agent_start_try (nmc); + + nmc->should_wait++; + nm_client_dbus_call (nmc->client, + NM_DBUS_PATH, + NM_DBUS_INTERFACE, + "Enable", + g_variant_new ("(b)", enable), + G_VARIANT_TYPE ("()"), + -1, + NULL, + _do_networking_on_off_cb, + nmc); } -static NMCResultCode -do_networking_connectivity (NmCli *nmc, int argc, char **argv) +static void +do_networking_connectivity (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { next_arg (nmc, &argc, &argv, NULL); if (nmc->complete) { if (argc == 1) nmc_complete_strings (*argv, "check"); - return nmc->return_value; + return; } if (!argc) { @@ -988,50 +999,41 @@ do_networking_connectivity (NmCli *nmc, int argc, char **argv) g_string_printf (nmc->return_text, _("Error: 'networking' command '%s' is not valid."), *argv); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; } - - return nmc->return_value; } -static NMCResultCode -do_networking_show (NmCli *nmc, int argc, char **argv) +static void +do_networking_show (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { next_arg (nmc, &argc, &argv, NULL); if (nmc->complete) - return nmc->return_value; + return; nmc_switch_show (nmc, NMC_FIELDS_NM_NETWORKING, N_("Networking")); - - return nmc->return_value; } -static const NMCCommand networking_cmds[] = { - { "on", do_networking_on, usage_networking_on, TRUE, TRUE }, - { "off", do_networking_off, usage_networking_off, TRUE, TRUE }, - { "connectivity", do_networking_connectivity, usage_networking_connectivity, TRUE, TRUE }, - { NULL, do_networking_show, usage_networking, TRUE, TRUE }, -}; - -/* - * Entry point function for networking commands 'nmcli networking' - */ -NMCResultCode -do_networking (NmCli *nmc, int argc, char **argv) +void +nmc_command_func_networking (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { - next_arg (nmc, &argc, &argv, NULL); - nmc_do_cmd (nmc, networking_cmds, *argv, argc, argv); + static const NMCCommand cmds[] = { + { "on", do_networking_on_off, usage_networking_on, TRUE, TRUE }, + { "off", do_networking_on_off, usage_networking_off, TRUE, TRUE }, + { "connectivity", do_networking_connectivity, usage_networking_connectivity, TRUE, TRUE }, + { NULL, do_networking_show, usage_networking, TRUE, TRUE }, + }; - return nmc->return_value; + next_arg (nmc, &argc, &argv, NULL); + nmc_do_cmd (nmc, cmds, *argv, argc, argv); } -static NMCResultCode -do_radio_all (NmCli *nmc, int argc, char **argv) +static void +do_radio_all (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { gboolean enable_flag; next_arg (nmc, &argc, &argv, NULL); if (argc == 0) { if (nmc->complete) - return nmc->return_value; + return; /* no argument, show all radio switches */ show_nm_status (nmc, N_("Radio switches"), NMC_FIELDS_NM_STATUS_RADIO); @@ -1039,29 +1041,42 @@ do_radio_all (NmCli *nmc, int argc, char **argv) if (nmc->complete) { if (argc == 1) nmc_complete_bool (*argv); - return nmc->return_value; + return; } if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag)) - return nmc->return_value; + return; nm_client_wireless_set_enabled (nmc->client, enable_flag); nm_client_wimax_set_enabled (nmc->client, enable_flag); nm_client_wwan_set_enabled (nmc->client, enable_flag); } +} + +static void +_do_radio_wifi_cb (GObject *object, GAsyncResult *result, gpointer user_data) +{ + NmCli *nmc = user_data; + gs_free_error GError *error = NULL; - return nmc->return_value; + if (!nm_client_dbus_set_property_finish (NM_CLIENT (object), result, &error)) { + g_dbus_error_strip_remote_error (error); + g_string_printf (nmc->return_text, _("Error: failed to set Wi-Fi radio: %s"), + nmc_error_get_simple_message (error)); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + } + quit (); } -static NMCResultCode -do_radio_wifi (NmCli *nmc, int argc, char **argv) +static void +do_radio_wifi (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { gboolean enable_flag; next_arg (nmc, &argc, &argv, NULL); if (argc == 0) { if (nmc->complete) - return nmc->return_value; + return; /* no argument, show current Wi-Fi state */ nmc_switch_show (nmc, NMC_FIELDS_NM_WIFI, N_("Wi-Fi radio switch")); @@ -1069,26 +1084,35 @@ do_radio_wifi (NmCli *nmc, int argc, char **argv) if (nmc->complete) { if (argc == 1) nmc_complete_bool (*argv); - return nmc->return_value; + return; } if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag)) - return nmc->return_value; + return; - nm_client_wireless_set_enabled (nmc->client, enable_flag); - } + nmc_start_polkit_agent_start_try (nmc); - return nmc->return_value; + nmc->should_wait++; + nm_client_dbus_set_property (nmc->client, + NM_DBUS_PATH, + NM_DBUS_INTERFACE, + "WirelessEnabled", + g_variant_new_boolean (enable_flag), + -1, + NULL, + _do_radio_wifi_cb, + nmc); + } } -static NMCResultCode -do_radio_wwan (NmCli *nmc, int argc, char **argv) +static void +do_radio_wwan (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { gboolean enable_flag; next_arg (nmc, &argc, &argv, NULL); if (argc == 0) { if (nmc->complete) - return nmc->return_value; + return; /* no argument, show current WWAN (mobile broadband) state */ nmc_switch_show (nmc, NMC_FIELDS_NM_WWAN, N_("WWAN radio switch")); @@ -1096,38 +1120,30 @@ do_radio_wwan (NmCli *nmc, int argc, char **argv) if (nmc->complete) { if (argc == 1) nmc_complete_bool (*argv); - return nmc->return_value; + return; } if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag)) - return nmc->return_value; + return; nm_client_wwan_set_enabled (nmc->client, enable_flag); } - - return nmc->return_value; } -static const NMCCommand radio_cmds[] = { - { "all", do_radio_all, usage_radio_all, TRUE, TRUE }, - { "wifi", do_radio_wifi, usage_radio_wifi, TRUE, TRUE }, - { "wwan", do_radio_wwan, usage_radio_wwan, TRUE, TRUE }, - { NULL, do_radio_all, usage_radio, TRUE, TRUE }, -}; - -/* - * Entry point function for radio switch commands 'nmcli radio' - */ -NMCResultCode -do_radio (NmCli *nmc, int argc, char **argv) +void +nmc_command_func_radio (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { + static const NMCCommand cmds[] = { + { "all", do_radio_all, usage_radio_all, TRUE, TRUE }, + { "wifi", do_radio_wifi, usage_radio_wifi, TRUE, TRUE }, + { "wwan", do_radio_wwan, usage_radio_wwan, TRUE, TRUE }, + { NULL, do_radio_all, usage_radio, TRUE, TRUE }, + }; + next_arg (nmc, &argc, &argv, NULL); - /* Register polkit agent */ nmc_start_polkit_agent_start_try (nmc); - nmc_do_cmd (nmc, radio_cmds, *argv, argc, argv); - - return nmc->return_value; + nmc_do_cmd (nmc, cmds, *argv, argc, argv); } static void @@ -1367,11 +1383,8 @@ ac_overview (NmCli *nmc, NMActiveConnection *ac) g_string_free (outbuf, TRUE); } -/* - * Entry point function for 'nmcli' without arguments. - */ -NMCResultCode -do_overview (NmCli *nmc, int argc, char **argv) +void +nmc_command_func_overview (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { NMDevice **devices; const GPtrArray *p; @@ -1386,7 +1399,7 @@ do_overview (NmCli *nmc, int argc, char **argv) /* Register polkit agent */ nmc_start_polkit_agent_start_try (nmc); - nm_cli_spawn_pager (nmc); + nm_cli_spawn_pager (&nmc->nmc_config, &nmc->pager_data); /* The VPN connections don't have devices (yet?). */ p = nm_client_get_active_connections (nmc->client); @@ -1481,20 +1494,15 @@ do_overview (NmCli *nmc, int argc, char **argv) "\"nmcli connection show\" to get an overview on active connection profiles.\n" "\n" "Consult nmcli(1) and nmcli-examples(7) manual pages for complete usage details.\n")); - - return NMC_RESULT_SUCCESS; } -/* - * Entry point function for 'nmcli monitor' - */ -NMCResultCode -do_monitor (NmCli *nmc, int argc, char **argv) +void +nmc_command_func_monitor (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv) { next_arg (nmc, &argc, &argv, NULL); if (nmc->complete) - return nmc->return_value; + return; if (argc > 0) { if (!nmc_arg_is_help (*argv)) { @@ -1503,7 +1511,7 @@ do_monitor (NmCli *nmc, int argc, char **argv) } usage_monitor (); - return nmc->return_value; + return; } if (!nm_client_get_nm_running (nmc->client)) { @@ -1530,6 +1538,4 @@ do_monitor (NmCli *nmc, int argc, char **argv) monitor_devices (nmc); monitor_connections (nmc); - - return NMC_RESULT_SUCCESS; } diff --git a/clients/cli/general.h b/clients/cli/general.h deleted file mode 100644 index dd63e43f..00000000 --- a/clients/cli/general.h +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2010 - 2014 Red Hat, Inc. - */ - -#ifndef NMC_GENERAL_H -#define NMC_GENERAL_H - -#include "nmcli.h" - -NMCResultCode do_general (NmCli *nmc, int argc, char **argv); -NMCResultCode do_networking (NmCli *nmc, int argc, char **argv); -NMCResultCode do_radio (NmCli *nmc, int argc, char **argv); -NMCResultCode do_monitor (NmCli *nmc, int argc, char **argv); -NMCResultCode do_overview (NmCli *nmc, int argc, char **argv); - -#endif /* NMC_GENERAL_H */ diff --git a/clients/cli/meson.build b/clients/cli/meson.build index 56202063..8dd05aff 100644 --- a/clients/cli/meson.build +++ b/clients/cli/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + name = 'nmcli' # FIXME: nmcli-completion should be renamed to nmcli @@ -6,33 +8,26 @@ install_data( install_dir: join_paths(nm_datadir, 'bash-completion', 'completions'), ) -sources = files( - 'agent.c', - 'common.c', - 'connections.c', - 'devices.c', - 'general.c', - 'nmcli.c', - 'polkit-agent.c', - 'settings.c', - 'utils.c', -) - deps = [ libnmc_base_dep, libnmc_dep, readline_dep, + libnm_libnm_aux_dep, ] -if enable_polkit_agent - sources += nm_polkit_listener - - deps += polkit_agent_dep -endif - executable( name, - sources, + files( + 'agent.c', + 'common.c', + 'connections.c', + 'devices.c', + 'general.c', + 'nmcli.c', + 'polkit-agent.c', + 'settings.c', + 'utils.c', + ), dependencies: deps, c_args: clients_c_flags + ['-DG_LOG_DOMAIN="@0@"'.format(name)], link_args: ldflags_linker_script_binary, diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c index 5fbd6d72..ee5ef015 100644 --- a/clients/cli/nmcli.c +++ b/clients/cli/nmcli.c @@ -25,8 +25,6 @@ #include "common.h" #include "connections.h" #include "devices.h" -#include "general.h" -#include "agent.h" #include "settings.h" #if defined(NM_DIST_VERSION) @@ -72,7 +70,7 @@ [NM_META_COLOR_ENABLED] = "32", \ [NM_META_COLOR_DISABLED] = "31", \ -NmCli nm_cli = { +static NmCli nm_cli = { .client = NULL, .return_value = NMC_RESULT_SUCCESS, @@ -101,6 +99,9 @@ NmCli nm_cli = { .editor_save_confirmation = TRUE, }; +const NmCli *const nm_cli_global_readline = &nm_cli; +const NmCli *const nmc_meta_environment_arg = &nm_cli; + /*****************************************************************************/ typedef struct { @@ -255,21 +256,21 @@ usage (void) "\n")); } -static const NMCCommand nmcli_cmds[] = { - { "general", do_general, NULL, FALSE, FALSE }, - { "monitor", do_monitor, NULL, TRUE, FALSE }, - { "networking", do_networking, NULL, FALSE, FALSE }, - { "radio", do_radio, NULL, FALSE, FALSE }, - { "connection", do_connections, NULL, FALSE, FALSE }, - { "device", do_devices, NULL, FALSE, FALSE }, - { "agent", do_agent, NULL, FALSE, FALSE }, - { NULL, do_overview, usage, TRUE, TRUE }, -}; - static gboolean -matches_arg (NmCli *nmc, int *argc, char ***argv, const char *pattern, char **arg) +matches_arg (NmCli *nmc, + int *argc, + const char *const**argv, + const char *pattern, + char **arg) { - char *opt = *argv[0]; + gs_free char *opt_free = NULL; + const char *opt = (*argv)[0]; + gs_free char *arg_tmp = NULL; + const char *s; + + nm_assert (opt); + nm_assert (opt[0] == '-'); + nm_assert (!arg || !*arg); if (nmc->return_value != NMC_RESULT_SUCCESS) { /* Don't process further matches if there has been an error. */ @@ -285,33 +286,31 @@ matches_arg (NmCli *nmc, int *argc, char ***argv, const char *pattern, char **ar if (arg) { /* If there's a "=" separator, replace it with NUL so that matches() * works and consider the part after it to be the arguemnt's value. */ - *arg = strchr (opt, '='); - if (*arg) { - **arg = '\0'; - (*arg)++; + s = strchr (opt, '='); + if (s) { + opt = nm_strndup_a (300, opt, s - opt, &opt_free); + arg_tmp = g_strdup (&s[1]); } } - if (!matches (opt, pattern)) { - if (arg && *arg) { - /* Back off the replacement of "=". */ - (*arg)--; - **arg = '='; - } + if (!matches (opt, pattern)) return FALSE; - } - if (arg && !*arg) { - /* We need a value, but the option didn't contain a "=<value>" part. - * Proceed to the next argument. */ - (*argc)--; - (*argv)++; - if (!*argc) { - g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return FALSE; + if (arg) { + if (arg_tmp) + *arg = g_steal_pointer (&arg_tmp); + else { + /* We need a value, but the option didn't contain a "=<value>" part. + * Proceed to the next argument. */ + if (*argc <= 1) { + g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return FALSE; + } + (*argc)--; + (*argv)++; + *arg = g_strdup (*argv[0]); } - *arg = *argv[0]; } return TRUE; @@ -697,26 +696,43 @@ set_colors (NmcColorOption color_option, /*************************************************************************************/ static gboolean -process_command_line (NmCli *nmc, int argc, char **argv) +process_command_line (NmCli *nmc, int argc, char **argv_orig) { + static const NMCCommand nmcli_cmds[] = { + { "general", nmc_command_func_general, NULL, FALSE, FALSE }, + { "monitor", nmc_command_func_monitor, NULL, TRUE, FALSE }, + { "networking", nmc_command_func_networking, NULL, FALSE, FALSE }, + { "radio", nmc_command_func_radio, NULL, FALSE, FALSE }, + { "connection", nmc_command_func_connection, NULL, FALSE, FALSE }, + { "device", nmc_command_func_device, NULL, FALSE, FALSE }, + { "agent", nmc_command_func_agent, NULL, FALSE, FALSE }, + { NULL, nmc_command_func_overview, usage, TRUE, TRUE }, + }; NmcColorOption colors = NMC_USE_COLOR_AUTO; - char *base; + const char *base; + const char *const*argv; - base = strrchr (argv[0], '/'); + base = strrchr (argv_orig[0], '/'); if (base == NULL) - base = argv[0]; + base = argv_orig[0]; else base++; - if (argc > 1 && nm_streq (argv[1], "--complete-args")) { + + if ( argc > 1 + && nm_streq (argv_orig[1], "--complete-args")) { nmc->complete = TRUE; - argv[1] = argv[0]; - next_arg (nmc, &argc, &argv, NULL); + argv_orig[1] = argv_orig[0]; + argc--; + argv_orig++; } + + argv = (const char *const*) argv_orig; + next_arg (nmc, &argc, &argv, NULL); /* parse options */ while (argc) { - char *value; + gs_free char *value = NULL; if (argv[0][0] != '-') break; @@ -909,11 +925,12 @@ signal_handler (gpointer user_data) } void -nm_cli_spawn_pager (NmCli *nmc) +nm_cli_spawn_pager (const NmcConfig *nmc_config, + NmcPagerData *pager_data) { - if (nmc->pager_pid > 0) + if (pager_data->pid != 0) return; - nmc->pager_pid = nmc_terminal_spawn_pager (&nmc->nmc_config); + pager_data->pid = nmc_terminal_spawn_pager (nmc_config); } static void @@ -935,13 +952,14 @@ nmc_cleanup (NmCli *nmc) nm_clear_g_free (&nmc->required_fields); - if (nmc->pager_pid > 0) { + if (nmc->pager_data.pid != 0) { + pid_t pid = nm_steal_int (&nmc->pager_data.pid); + fclose (stdout); fclose (stderr); do { - ret = waitpid (nmc->pager_pid, NULL, 0); + ret = waitpid (pid, NULL, 0); } while (ret == -1 && errno == EINTR); - nmc->pager_pid = 0; } nm_clear_g_free (&nmc->palette_buffer); diff --git a/clients/cli/nmcli.h b/clients/cli/nmcli.h index 4615b046..c8d27b3d 100644 --- a/clients/cli/nmcli.h +++ b/clients/cli/nmcli.h @@ -101,6 +101,10 @@ typedef struct _NmcConfig { const char *palette[_NM_META_COLOR_NUM]; /* Color palette */ } NmcConfig; +typedef struct { + pid_t pid; +} NmcPagerData; + typedef struct _NmcOutputData { GPtrArray *output_data; /* GPtrArray of arrays of NmcOutputField structs - accumulates data for output */ } NmcOutputData; @@ -111,7 +115,8 @@ typedef struct _NmCli { NMCResultCode return_value; /* Return code of nmcli */ GString *return_text; /* Reason text */ - pid_t pager_pid; /* PID of a pager, if one was spawned */ + + NmcPagerData pager_data; int timeout; /* Operation timeout */ @@ -135,7 +140,7 @@ typedef struct _NmCli { char *palette_buffer; /* Buffer with sequences for terminal-colors.d(5)-based coloring. */ } NmCli; -extern NmCli nm_cli; +extern const NmCli *const nm_cli_global_readline; /* Error quark for GError domain */ #define NMCLI_ERROR (nmcli_error_quark ()) @@ -148,7 +153,8 @@ void nmc_clear_sigint (void); void nmc_set_sigquit_internal (void); void nmc_exit (void); -void nm_cli_spawn_pager (NmCli *nmc); +void nm_cli_spawn_pager (const NmcConfig *nmc_config, + NmcPagerData *pager_data); void nmc_empty_output_fields (NmcOutputData *output_data); @@ -158,4 +164,27 @@ void nmc_empty_output_fields (NmcOutputData *output_data); .output_data = g_ptr_array_new_full (20, g_free), \ } +/*****************************************************************************/ + +struct _NMCCommand; + +typedef struct _NMCCommand { + const char *cmd; + void (*func) (const struct _NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv); + void (*usage) (void); + bool needs_client; + bool needs_nm_running; +} NMCCommand; + +void nmc_command_func_agent (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv); +void nmc_command_func_general (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv); +void nmc_command_func_networking (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv); +void nmc_command_func_radio (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv); +void nmc_command_func_monitor (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv); +void nmc_command_func_overview (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv); +void nmc_command_func_connection (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv); +void nmc_command_func_device (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv); + +/*****************************************************************************/ + #endif /* NMC_NMCLI_H */ diff --git a/clients/cli/polkit-agent.c b/clients/cli/polkit-agent.c index 69bfb68d..183562e7 100644 --- a/clients/cli/polkit-agent.c +++ b/clients/cli/polkit-agent.c @@ -14,16 +14,12 @@ #include "nm-polkit-listener.h" #include "common.h" -#if WITH_POLKIT_AGENT static char * -polkit_request (NMPolkitListener *listener, - const char *request, - const char *action_id, - const char *message, - const char *icon_name, - const char *user, - gboolean echo_on, - gpointer user_data) +polkit_read_passwd (gpointer instance, + const char *action_id, + const char *message, + const char *user, + gpointer user_data) { NmCli *nmc = user_data; @@ -32,87 +28,68 @@ polkit_request (NMPolkitListener *listener, /* 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 && nm_streq (p, ": ")) - *p = '\0'; - return nmc_readline_echo (&nmc->nmc_config, echo_on, "%s (%s): ", tmp, user); + return nmc_readline_echo (&nmc->nmc_config, FALSE, "password (%s): ", user); } - - return nmc_readline_echo (&nmc->nmc_config, echo_on, "%s", request); + return nmc_readline_echo (&nmc->nmc_config, FALSE, "password: "); } static void -polkit_show_info (NMPolkitListener *listener, - const char *text, - gpointer user_data) +polkit_error (gpointer instance, + const char *error, + gpointer user_data) { - g_print (_("Authentication message: %s\n"), text); + g_printerr (_("Error: polkit agent failed: %s\n"), error); } -static void -polkit_show_error (NMPolkitListener *listener, - const char *text, - gpointer user_data) -{ - g_print (_("Authentication error: %s\n"), text); -} - -static void -polkit_completed (NMPolkitListener *listener, - gboolean gained_authorization, - gpointer user_data) -{ - /* We don't print anything here. The outcome will be evident from - * the operation result anyway. */ -} -#endif - gboolean nmc_polkit_agent_init (NmCli* nmc, gboolean for_session, GError **error) { -#if WITH_POLKIT_AGENT - static const NMPolkitListenVtable vtable = { - .on_request = polkit_request, - .on_show_info = polkit_show_info, - .on_show_error = polkit_show_error, - .on_completed = polkit_completed, - }; NMPolkitListener *listener; + GDBusConnection *dbus_connection = NULL; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - listener = nm_polkit_listener_new (for_session, error); - if (!listener) - return FALSE; + if (nmc->client && nm_client_get_dbus_connection (nmc->client)) { + dbus_connection = nm_client_get_dbus_connection (nmc->client); + listener = nm_polkit_listener_new (dbus_connection, for_session); + } else { + dbus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, + NULL, + error); + + if (!dbus_connection) { + return FALSE; + } + + listener = nm_polkit_listener_new (dbus_connection, for_session); + g_object_unref (dbus_connection); + } - nm_polkit_listener_set_vtable (listener, &vtable, nmc); + g_signal_connect (listener, + NM_POLKIT_LISTENER_SIGNAL_REQUEST_SYNC, + G_CALLBACK (polkit_read_passwd), + nmc); + g_signal_connect (listener, + NM_POLKIT_LISTENER_SIGNAL_ERROR, + G_CALLBACK (polkit_error), + NULL); nmc->pk_listener = listener; -#endif return TRUE; } void nmc_polkit_agent_fini (NmCli* nmc) { -#if WITH_POLKIT_AGENT if (nmc->pk_listener) { - nm_polkit_listener_set_vtable (nmc->pk_listener, NULL, NULL); g_clear_object (&nmc->pk_listener); } -#endif } gboolean nmc_start_polkit_agent_start_try (NmCli *nmc) { -#if WITH_POLKIT_AGENT - GError *error = NULL; + gs_free_error GError *error = NULL; /* We don't register polkit agent at all when running non-interactively */ if (!nmc->ask) @@ -121,9 +98,7 @@ nmc_start_polkit_agent_start_try (NmCli *nmc) if (!nmc_polkit_agent_init (nmc, FALSE, &error)) { g_printerr (_("Warning: polkit agent initialization failed: %s\n"), error->message); - g_error_free (error); return FALSE; } -#endif return TRUE; } diff --git a/clients/cli/settings.c b/clients/cli/settings.c index 698471d7..0487fb96 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -456,8 +456,6 @@ const NMMetaEnvironment *const nmc_meta_environment = &((NMMetaEnvironment) { .get_nm_connections = _env_get_nm_connections, }); -NmCli *const nmc_meta_environment_arg = &nm_cli; - static char * get_property_val (NMSetting *setting, const char *prop, NMMetaAccessorGetType get_type, gboolean show_secrets, GError **error) { @@ -475,7 +473,7 @@ get_property_val (NMSetting *setting, const char *prop, NMMetaAccessorGetType ge value = property_info->property_type->get_fcn (property_info, nmc_meta_environment, - nmc_meta_environment_arg, + (gpointer) nmc_meta_environment_arg, setting, get_type, show_secrets ? NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS : 0, @@ -568,7 +566,7 @@ nmc_setting_set_property (NMClient *client, g_object_freeze_notify (G_OBJECT (setting)); success = property_info->property_type->set_fcn (property_info, nmc_meta_environment, - nmc_meta_environment_arg, + (gpointer) nmc_meta_environment_arg, setting, modifier, value, diff --git a/clients/cli/utils.c b/clients/cli/utils.c index 2e3a38f7..d0d553b9 100644 --- a/clients/cli/utils.c +++ b/clients/cli/utils.c @@ -154,7 +154,7 @@ parse_global_arg (NmCli *nmc, const char *arg) * -1 otherwise (no more args). */ int -next_arg (NmCli *nmc, int *argc, char ***argv, ...) +next_arg (NmCli *nmc, int *argc, const char *const**argv, ...) { va_list args; const char *cmd_option; @@ -248,7 +248,7 @@ nmc_arg_is_option (const char *str, const char *opt_name) * Returns: TRUE on success, FALSE on an error and sets 'error' */ gboolean -nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***argv, GError **error) +nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, const char *const**argv, GError **error) { nmc_arg_t *p; gboolean found; @@ -321,19 +321,14 @@ nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***argv, GErr char * ssid_to_hex (const char *str, gsize len) { - GString *printable; - char *printable_str; - int i; - - if (str == NULL || len == 0) + if (len == 0) return NULL; - printable = g_string_new (NULL); - for (i = 0; i < len; i++) { - g_string_append_printf (printable, "%02X", (unsigned char) str[i]); - } - printable_str = g_string_free (printable, FALSE); - return printable_str; + return nm_utils_bin2hexstr_full (str, + len, + '\0', + TRUE, + NULL); } /* @@ -667,7 +662,6 @@ _output_selection_append (GArray *cols, guint i; const NMMetaAbstractInfo *const*nested; NMMetaSelectionResultList *selection; - const NMMetaSelectionItem *si; col_idx = cols->len; @@ -688,6 +682,8 @@ _output_selection_append (GArray *cols, gs_free char *allowed_fields = NULL; if (parent_idx != PRINT_DATA_COL_PARENT_NIL) { + const NMMetaSelectionItem *si; + si = g_array_index (cols, PrintDataCol, parent_idx).selection_item; allowed_fields = nm_meta_abstract_info_get_nested_names_str (si->info, si->self_selection); } @@ -719,10 +715,9 @@ _output_selection_append (GArray *cols, g_ptr_array_add (gfree_keeper, selection); for (i = 0; i < selection->num; i++) { - si = &selection->items[i]; if (!_output_selection_append (cols, col_idx, - si, + &selection->items[i], gfree_keeper, error)) return FALSE; @@ -778,7 +773,8 @@ _output_selection_complete (GArray *cols) static gboolean _output_selection_parse (const NMMetaAbstractInfo *const*fields, const char *fields_str, - GArray **out_cols, + PrintDataCol **out_cols_data, + guint *out_cols_len, GPtrArray **out_gfree_keeper, GError **error) { @@ -803,16 +799,18 @@ _output_selection_parse (const NMMetaAbstractInfo *const*fields, cols = g_array_new (FALSE, TRUE, sizeof (PrintDataCol)); for (i = 0; i < selection->num; i++) { - const NMMetaSelectionItem *si = &selection->items[i]; - - if (!_output_selection_append (cols, PRINT_DATA_COL_PARENT_NIL, - si, gfree_keeper, error)) + if (!_output_selection_append (cols, + PRINT_DATA_COL_PARENT_NIL, + &selection->items[i], + gfree_keeper, + error)) return FALSE; } _output_selection_complete (cols); - *out_cols = g_steal_pointer (&cols); + *out_cols_len = cols->len; + *out_cols_data = (PrintDataCol *) g_array_free (g_steal_pointer (&cols), FALSE); *out_gfree_keeper = g_steal_pointer (&gfree_keeper); return TRUE; } @@ -1069,7 +1067,7 @@ _print_fill (const NmcConfig *nmc_config, value = nm_meta_abstract_info_get (info, nmc_meta_environment, - nmc_meta_environment_arg, + (gpointer) nmc_meta_environment_arg, target, targets_data, text_get_type, @@ -1114,7 +1112,7 @@ _print_fill (const NmcConfig *nmc_config, cell->color = GPOINTER_TO_INT (nm_meta_abstract_info_get (info, nmc_meta_environment, - nmc_meta_environment_arg, + (gpointer) nmc_meta_environment_arg, target, targets_data, NM_META_ACCESSOR_GET_TYPE_COLOR, @@ -1142,7 +1140,8 @@ _print_fill (const NmcConfig *nmc_config, header_cell->width = nmc_string_screen_width (header_cell->title, NULL); for (i_row = 0; i_row < targets_len; i_row++) { - const PrintDataCell *cell = &g_array_index (cells, PrintDataCell, i_row * cols_len + i_col); + const PrintDataCell *cells_line = &g_array_index (cells, PrintDataCell, i_row * header_row->len); + const PrintDataCell *cell = &cells_line[i_col]; const char *const*i_strv; switch (cell->text_format) { @@ -1379,20 +1378,24 @@ nmc_print (const NmcConfig *nmc_config, GError **error) { gs_unref_ptrarray GPtrArray *gfree_keeper = NULL; - gs_unref_array GArray *cols = NULL; + gs_free PrintDataCol *cols_data = NULL; + guint cols_len; gs_unref_array GArray *header_row = NULL; gs_unref_array GArray *cells = NULL; - if (!_output_selection_parse (fields, fields_str, - &cols, &gfree_keeper, + if (!_output_selection_parse (fields, + fields_str, + &cols_data, + &cols_len, + &gfree_keeper, error)) return FALSE; _print_fill (nmc_config, targets, targets_data, - &g_array_index (cols, PrintDataCol, 0), - cols->len, + cols_data, + cols_len, &header_row, &cells); @@ -1568,6 +1571,7 @@ get_value_to_print (const NmcConfig *nmc_config, */ void print_required_fields (const NmcConfig *nmc_config, + NmcPagerData *pager_data, NmcOfFlags of_flags, const GArray *indices, const char *header_name, @@ -1584,7 +1588,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; - nm_cli_spawn_pager (&nm_cli); + nm_cli_spawn_pager (nmc_config, pager_data); /* --- Main header --- */ if ( nmc_config->print_output == NMC_PRINT_PRETTY @@ -1793,6 +1797,7 @@ print_data_prepare_width (GPtrArray *output_data) void print_data (const NmcConfig *nmc_config, + NmcPagerData *pager_data, const GArray *indices, const char *header_name, int indent, @@ -1803,9 +1808,13 @@ print_data (const NmcConfig *nmc_config, for (i = 0; i < out->output_data->len; i++) { const NmcOutputField *field_values = g_ptr_array_index (out->output_data, i); - print_required_fields (nmc_config, field_values[0].flags, - indices, header_name, - indent, field_values); + print_required_fields (nmc_config, + pager_data, + field_values[0].flags, + indices, + header_name, + indent, + field_values); } } diff --git a/clients/cli/utils.h b/clients/cli/utils.h index e699a641..76f5bae0 100644 --- a/clients/cli/utils.h +++ b/clients/cli/utils.h @@ -19,10 +19,10 @@ typedef struct { } nmc_arg_t; /* === Functions === */ -int next_arg (NmCli *nmc, int *argc, char ***argv, ...); +int next_arg (NmCli *nmc, int *argc, const char *const**argv, ...); gboolean nmc_arg_is_help (const char *arg); gboolean nmc_arg_is_option (const char *arg, const char *opt_name); -gboolean nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***argv, GError **error); +gboolean nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, const char *const**argv, GError **error); char *ssid_to_hex (const char *str, gsize len); void nmc_terminal_erase_line (void); void nmc_terminal_show_progress (const char *str); @@ -51,6 +51,7 @@ GArray *parse_output_fields (const char *fields_str, NmcOutputField *nmc_dup_fields_array (const NMMetaAbstractInfo *const*fields, NmcOfFlags flags); void nmc_empty_output_fields (NmcOutputData *output_data); void print_required_fields (const NmcConfig *nmc_config, + NmcPagerData *pager_data, NmcOfFlags of_flags, const GArray *indices, const char *header_name, @@ -58,6 +59,7 @@ void print_required_fields (const NmcConfig *nmc_config, const NmcOutputField *field_values); void print_data_prepare_width (GPtrArray *output_data); void print_data (const NmcConfig *nmc_config, + NmcPagerData *pager_data, const GArray *indices, const char *header_name, int indent, @@ -66,7 +68,7 @@ void print_data (const NmcConfig *nmc_config, /*****************************************************************************/ extern const NMMetaEnvironment *const nmc_meta_environment; -extern NmCli *const nmc_meta_environment_arg; +extern const NmCli *const nmc_meta_environment_arg; typedef enum { |