From 9959fdb2e8ddd06f2161798ca0a39c77d67c652d Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Wed, 4 May 2022 15:35:24 +0200 Subject: New upstream version 1.37.92 --- src/nmcli/common.c | 8 +- src/nmcli/connections.c | 337 +++++++++++++++++++---- src/nmcli/devices.c | 155 ++++++----- src/nmcli/general.c | 10 + src/nmcli/generate-docs-nm-settings-nmcli.xml | 8 +- src/nmcli/generate-docs-nm-settings-nmcli.xml.in | 8 +- src/nmcli/nmcli.c | 14 +- src/nmcli/utils.c | 6 +- 8 files changed, 391 insertions(+), 155 deletions(-) (limited to 'src/nmcli') diff --git a/src/nmcli/common.c b/src/nmcli/common.c index 26398c84..f42f76e4 100644 --- a/src/nmcli/common.c +++ b/src/nmcli/common.c @@ -889,13 +889,7 @@ nmc_readline_helper(const NmcConfig *nmc_config, const char *prompt) nmc_set_in_readline(TRUE); - 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); + io_source = nm_g_unix_fd_add_source(STDIN_FILENO, G_IO_IN, stdin_ready_cb, NULL); read_again: rl_string = NULL; diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c index 025f96a1..ecf8e2e2 100644 --- a/src/nmcli/connections.c +++ b/src/nmcli/connections.c @@ -513,6 +513,40 @@ _con_show_fcn_get_type(NMConnection *c, NMActiveConnection *ac, NMMetaAccessorGe return connection_type_to_display(s, get_type); } +static const char * +_connection_check_deprecated(NMConnection *c) +{ + NMSettingWirelessSecurity *s_wsec; + const char *key_mgmt; + const char *type; + + type = nm_connection_get_connection_type(c); + + if (strcmp(type, NM_SETTING_WIMAX_SETTING_NAME) == 0) + return _("WiMax is no longer supported"); + + s_wsec = nm_connection_get_setting_wireless_security(c); + if (s_wsec) { + key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); + if (NM_IN_STRSET(key_mgmt, "ieee8021x", "none")) + return _("WEP encryption is known to be insecure"); + } + + return NULL; +} + +static NMMetaColor +_connection_to_color(NMConnection *c, NMActiveConnection *ac) +{ + if (ac) + return nmc_active_connection_state_to_color(ac); + + if (_connection_check_deprecated(c)) + return NM_META_COLOR_CONNECTION_DEPRECATED; + + return NM_META_COLOR_CONNECTION_UNKNOWN; +} + static gconstpointer _metagen_con_show_get_fcn(NMC_META_GENERIC_INFO_GET_FCN_ARGS) { @@ -523,7 +557,7 @@ _metagen_con_show_get_fcn(NMC_META_GENERIC_INFO_GET_FCN_ARGS) const char *s; char *s_mut; - NMC_HANDLE_COLOR(nmc_active_connection_state_to_color(ac)); + NMC_HANDLE_COLOR(_connection_to_color(c, ac)); if (c) s_con = nm_connection_get_setting_connection(c); @@ -1197,10 +1231,10 @@ usage_connection_delete(void) { g_printerr(_("Usage: nmcli connection delete { ARGUMENTS | help }\n" "\n" - "ARGUMENTS := [id | uuid | path] \n" + "ARGUMENTS := [id | uuid | path] , ...\n" "\n" - "Delete a connection profile.\n" - "The profile is identified by its name, UUID or D-Bus path.\n\n")); + "Delete connection profiles.\n" + "The profiles are identified by their name, UUID or D-Bus path.\n\n")); } static void @@ -1260,6 +1294,17 @@ usage_connection_export(void) "The data are directed to standard output or to a file if a name is given.\n\n")); } +static void +usage_connection_migrate(void) +{ + g_printerr(_("Usage: nmcli connection migrate { ARGUMENTS | help }\n" + "\n" + "ARGUMENTS := [--plugin ] [id | uuid | path] , ...\n" + "\n" + "Migrate connection profiles to a different settings plugin,\n" + "such as \"keyfile\" (default) or \"ifcfg-rh\".\n\n")); +} + static void quit(void) { @@ -1410,13 +1455,13 @@ nmc_connection_profile_details(NMConnection *connection, NmCli *nmc) TRUE, &prop_array, &error); - if (error) { + if (!print_settings_array) { + g_return_val_if_fail(error, FALSE); g_string_printf(nmc->return_text, _("Error: 'connection show': %s"), error->message); g_error_free(error); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; return FALSE; } - g_assert(print_settings_array); /* Main header */ { @@ -1478,9 +1523,6 @@ nmc_active_connection_state_to_color(NMActiveConnection *ac) { NMActiveConnectionState state; - if (!ac) - return NM_META_COLOR_CONNECTION_UNKNOWN; - if (NM_FLAGS_HAS(nm_active_connection_get_state_flags(ac), NM_ACTIVATION_STATE_FLAG_EXTERNAL)) return NM_META_COLOR_CONNECTION_EXTERNAL; @@ -1520,13 +1562,13 @@ nmc_active_connection_details(NMActiveConnection *acon, NmCli *nmc) TRUE, &group_fields, &error); - if (error) { + if (!print_groups) { + g_return_val_if_fail(error, FALSE); g_string_printf(nmc->return_text, _("Error: 'connection show': %s"), error->message); g_error_free(error); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; return FALSE; } - g_assert(print_groups); /* Main header */ { @@ -1881,6 +1923,7 @@ con_show_get_items_cmp(gconstpointer pa, gconstpointer pb, gpointer user_data) } } + NM_CMP_DIRECT(!!_connection_check_deprecated(c_a), !!_connection_check_deprecated(c_b)); NM_CMP_DIRECT_STRCMP0(nm_connection_get_uuid(c_a), nm_connection_get_uuid(c_b)); NM_CMP_DIRECT_STRCMP0(nm_connection_get_path(c_a), nm_connection_get_path(c_b)); } @@ -2150,7 +2193,7 @@ do_connections_show(const NMCCommand *cmd, NmCli *nmc, int argc, const char *con goto finish; break; default: - g_assert_not_reached(); + g_return_if_reached(); break; } } @@ -2470,7 +2513,7 @@ find_device_for_connection(NmCli *nmc, g_return_val_if_fail(error == NULL || *error == NULL, FALSE); s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); + g_return_val_if_fail(s_con, FALSE); con_type = nm_setting_connection_get_connection_type(s_con); if (nm_streq(con_type, NM_SETTING_VPN_SETTING_NAME)) { @@ -2959,7 +3002,7 @@ do_connection_up(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const gs_free char *line = NULL; /* nmc_do_cmd() should not call this with argc=0. */ - g_assert(!nmc->complete); + g_return_if_fail(!nmc->complete); line = nmc_readline(&nmc->nmc_config, PROMPT_CONNECTION); nmc_string_to_arg_array(line, NULL, TRUE, &arg_arr, &arg_num); @@ -3215,7 +3258,7 @@ do_connection_down(const NMCCommand *cmd, NmCli *nmc, int argc, const char *cons if (argc == 0) { /* nmc_do_cmd() should not call this with argc=0. */ - g_assert(!nmc->complete); + g_return_if_fail(!nmc->complete); if (nmc->ask) { gs_free char *line = NULL; @@ -3660,7 +3703,8 @@ is_setting_mandatory(NMConnection *connection, NMSetting *setting) guint i; s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); + g_return_val_if_fail(s_con, FALSE); + c_type = nm_setting_connection_get_connection_type(s_con); s_type = nm_setting_connection_get_slave_type(s_con); @@ -3739,7 +3783,7 @@ normalized_master_for_slave(const GPtrArray *connections, for (i = 0; i < connections->len; i++) { connection = NM_CONNECTION(connections->pdata[i]); s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); + g_return_val_if_fail(s_con, NULL); con_type = nm_setting_connection_get_connection_type(s_con); if (type && !nm_streq0(con_type, type)) continue; @@ -4243,7 +4287,7 @@ con_settings(NMConnection *connection, g_return_val_if_fail(slv_settings, FALSE); s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); + g_return_val_if_fail(s_con, FALSE); con_type = nm_setting_connection_get_slave_type(s_con); *slv_settings = nm_meta_setting_info_valid_parts_for_slave_type(con_type, NULL); @@ -5208,6 +5252,46 @@ nmc_process_connection_properties(NmCli *nmc, return TRUE; } +static void +connection_warnings(NmCli *nmc, NMConnection *connection) +{ + const GPtrArray *connections; + guint i, found; + const char *id; + const char *deprecated; + + deprecated = _connection_check_deprecated(NM_CONNECTION(connection)); + if (deprecated) + g_printerr(_("Warning: %s.\n"), deprecated); + + connections = nm_client_get_connections(nmc->client); + if (!connections) + return; + + id = nm_connection_get_id(connection); + found = 0; + for (i = 0; i < connections->len; i++) { + NMConnection *candidate = NM_CONNECTION(connections->pdata[i]); + + if ((NMConnection *) connection == candidate) + continue; + if (nm_streq0(nm_connection_get_id(candidate), id)) + found++; + } + + if (found > 0) { + g_printerr(g_dngettext(GETTEXT_PACKAGE, + "Warning: There is another connection with the name '%1$s'. " + "Reference the connection by its uuid '%2$s'\n", + "Warning: There are %3$u other connections with the name " + "'%1$s'. Reference the connection by its uuid '%2$s'\n", + found), + id, + nm_connection_get_uuid(NM_CONNECTION(connection)), + found); + } +} + static void add_connection_cb(GObject *client, GAsyncResult *result, gpointer user_data) { @@ -5215,8 +5299,6 @@ add_connection_cb(GObject *client, GAsyncResult *result, gpointer user_data) NmCli *nmc = info->nmc; NMRemoteConnection *connection; GError *error = NULL; - const GPtrArray *connections; - guint i, found; connection = nm_client_add_connection2_finish(NM_CLIENT(client), result, NULL, &error); if (error) { @@ -5227,29 +5309,7 @@ add_connection_cb(GObject *client, GAsyncResult *result, gpointer user_data) g_error_free(error); nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; } else { - connections = nm_client_get_connections(nmc->client); - if (connections) { - found = 0; - for (i = 0; i < connections->len; i++) { - NMConnection *candidate = NM_CONNECTION(connections->pdata[i]); - - if ((NMConnection *) connection == candidate) - continue; - if (nm_streq0(nm_connection_get_id(candidate), info->new_id)) - found++; - } - if (found > 0) { - g_printerr(g_dngettext(GETTEXT_PACKAGE, - "Warning: There is another connection with the name '%1$s'. " - "Reference the connection by its uuid '%2$s'\n", - "Warning: There are %3$u other connections with the name " - "'%1$s'. Reference the connection by its uuid '%2$s'\n", - found), - info->new_id, - nm_connection_get_uuid(NM_CONNECTION(connection)), - found); - } - } + connection_warnings(nmc, NM_CONNECTION(connection)); /* We print here human readable text, but as scripts might parse this output * (with LANG=C), this is important to not change in the future. At least @@ -7252,7 +7312,8 @@ editor_show_status_line(NMConnection *connection, gboolean dirty, gboolean temp) const char *con_type, *con_id, *con_uuid; s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); + g_return_if_fail(s_con); + con_type = nm_setting_connection_get_connection_type(s_con); con_id = nm_connection_get_id(connection); con_uuid = nm_connection_get_uuid(connection); @@ -7595,15 +7656,18 @@ confirm_connection_saving(const NmcConfig *nmc_config, NMConnection *local, NMCo gboolean confirmed = TRUE; s_con_loc = nm_connection_get_setting_connection(local); - g_assert(s_con_loc); + g_return_val_if_fail(s_con_loc, FALSE); + ac_local = nm_setting_connection_get_autoconnect(s_con_loc); if (remote) { s_con_rem = nm_connection_get_setting_connection(remote); - g_assert(s_con_rem); + g_return_val_if_fail(s_con_rem, FALSE); + ac_remote = nm_setting_connection_get_autoconnect(s_con_rem); - } else + } else { ac_remote = FALSE; + } if (ac_local && !ac_remote) { gs_free char *answer = NULL; @@ -8280,9 +8344,12 @@ editor_menu_main(NmCli *nmc, NMConnection *connection, const char *connection_ty connection_changed = FALSE; } - 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)); + source = nm_g_source_attach(nm_g_timeout_source_new(10 * NM_UTILS_MSEC_PER_SEC, + G_PRIORITY_DEFAULT, + editor_save_timeout, + &timeout, + NULL), + g_main_loop_get_context(loop)); while (!nmc_editor_cb_called && !timeout) g_main_context_iteration(NULL, TRUE); @@ -8527,7 +8594,8 @@ editor_init_new_connection(NmCli *nmc, NMConnection *connection, const char *sla const char *con_type; s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); + g_return_if_fail(s_con); + con_type = nm_setting_connection_get_connection_type(s_con); /* Initialize new connection according to its type using sensible defaults. */ @@ -8851,6 +8919,8 @@ modify_connection_cb(GObject *connection, GAsyncResult *result, gpointer user_da error->message); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; } else { + connection_warnings(nmc, NM_CONNECTION(connection)); + if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) { g_print(_("Connection '%s' (%s) successfully modified.\n"), nm_connection_get_id(NM_CONNECTION(connection)), @@ -8955,7 +9025,7 @@ do_connection_clone(const NMCCommand *cmd, NmCli *nmc, int argc, const char *con gs_free char *line = NULL; /* nmc_do_cmd() should not call this with argc=0. */ - g_assert(!nmc->complete); + g_return_if_fail(!nmc->complete); line = nmc_readline(&nmc->nmc_config, PROMPT_CONNECTION); nmc_string_to_arg_array(line, NULL, TRUE, &arg_arr, &arg_num); @@ -9054,7 +9124,7 @@ do_connection_delete(const NMCCommand *cmd, NmCli *nmc, int argc, const char *co gs_free char *line = NULL; /* nmc_do_cmd() should not call this with argc=0. */ - g_assert(!nmc->complete); + g_return_if_fail(!nmc->complete); line = nmc_readline(&nmc->nmc_config, PROMPT_CONNECTIONS); nmc_string_to_arg_array(line, NULL, TRUE, &arg_arr, &arg_num); @@ -9079,8 +9149,11 @@ do_connection_delete(const NMCCommand *cmd, NmCli *nmc, int argc, const char *co nmc->return_value = error->code; g_clear_error(&error); - if (nmc->return_value != NMC_RESULT_ERROR_NOT_FOUND) + if (nmc->return_value != NMC_RESULT_ERROR_NOT_FOUND) { + g_string_free(invalid_cons, TRUE); + invalid_cons = NULL; goto finish; + } if (!invalid_cons) invalid_cons = g_string_new(NULL); @@ -9133,7 +9206,6 @@ finish: g_string_printf(nmc->return_text, _("Error: cannot delete unknown connection(s): %s."), invalid_cons->str); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; } } @@ -9192,7 +9264,7 @@ do_connection_monitor(const NMCCommand *cmd, NmCli *nmc, int argc, const char *c /* No connections specified. Monitor all. */ /* nmc_do_cmd() should not call this with argc=0. */ - g_assert(!nmc->complete); + g_return_if_fail(!nmc->complete); connections = nm_client_get_connections(nmc->client); } else { @@ -9349,7 +9421,7 @@ do_connection_import(const NMCCommand *cmd, NmCli *nmc, int argc, const char *co if (argc == 0) { /* nmc_do_cmd() should not call this with argc=0. */ - g_assert(!nmc->complete); + g_return_if_fail(!nmc->complete); if (nmc->ask) { type_ask = @@ -9492,7 +9564,7 @@ do_connection_export(const NMCCommand *cmd, NmCli *nmc, int argc, const char *co gs_free char *line = NULL; /* nmc_do_cmd() should not call this with argc=0. */ - g_assert(!nmc->complete); + g_return_if_fail(!nmc->complete); line = nmc_readline(&nmc->nmc_config, PROMPT_VPN_CONNECTION); nmc_string_to_arg_array(line, NULL, TRUE, &arg_arr, &arg_num); @@ -9586,6 +9658,154 @@ finish: unlink(path); } +static void +migrate_cb(GObject *obj, GAsyncResult *result, gpointer user_data) +{ + ConnectionCbInfo *info = (ConnectionCbInfo *) user_data; + NMConnection *connection = NM_CONNECTION(obj); + gs_unref_variant GVariant *res = NULL; + GError *error = NULL; + + res = nm_remote_connection_update2_finish(NM_REMOTE_CONNECTION(obj), result, &error); + if (!res) { + g_string_printf(info->nmc->return_text, _("Error: not all connections migrated.")); + g_printerr(_("Error: Connection migration failed: %s\n"), error->message); + g_error_free(error); + info->nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + } else { + g_print(_("Connection '%s' (%s) successfully migrated.\n"), + nm_connection_get_id(connection), + nm_connection_get_uuid(connection)); + } + connection_cb_info_finish(info, obj); +} + +static void +do_connection_migrate(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) +{ + NMConnection *connection; + ConnectionCbInfo *info = NULL; + gs_strfreev char **arg_arr = NULL; + const char *const *arg_ptr; + guint i; + int arg_num; + nm_auto_free_gstring GString *invalid_cons = NULL; + gs_unref_ptrarray GPtrArray *found_cons = NULL; + GError *error = NULL; + const char *plugin = "keyfile"; + const GPtrArray *connections = NULL; + int option; + + if (nmc->timeout == -1) + nmc->timeout = 10; + + while ((option = next_arg(nmc, &argc, &argv, "--plugin", NULL)) > 0) { + switch (option) { + case 1: /* --plugin */ + argc--; + argv++; + if (!argc) { + g_set_error_literal(&error, NMCLI_ERROR, 0, _("'--plugin' argument is missing")); + goto finish; + } + plugin = *argv; + break; + default: + g_return_if_reached(); + break; + } + } + + arg_ptr = argv; + arg_num = argc; + if (argc == 0) { + if (nmc->ask) { + gs_free char *line = NULL; + + /* nmc_do_cmd() should not call this with argc=0. */ + g_return_if_fail(!nmc->complete); + + line = nmc_readline(&nmc->nmc_config, PROMPT_CONNECTIONS); + nmc_string_to_arg_array(line, NULL, TRUE, &arg_arr, &arg_num); + arg_ptr = (const char *const *) arg_arr; + } + } + + while (arg_num > 0) { + const char *cur_selector, *cur_value; + + connection = + get_connection(nmc, &arg_num, &arg_ptr, &cur_selector, &cur_value, &found_cons, &error); + if (!connection) { + if (!nmc->complete) + g_printerr(_("Error: %s.\n"), error->message); + g_string_printf(nmc->return_text, _("Error: not all connections found.")); + nmc->return_value = error->code; + g_clear_error(&error); + + if (nmc->return_value != NMC_RESULT_ERROR_NOT_FOUND) { + g_string_free(invalid_cons, TRUE); + invalid_cons = NULL; + goto finish; + } + + if (!invalid_cons) + invalid_cons = g_string_new(NULL); + if (cur_selector) + g_string_append_printf(invalid_cons, "%s '%s', ", cur_selector, cur_value); + else + g_string_append_printf(invalid_cons, "'%s', ", cur_value); + } + } + + if (nmc->complete) + goto finish; + + if (invalid_cons) + goto finish; + + if (!found_cons) { + /* No connections specified explicitly? Fine, add all. */ + found_cons = g_ptr_array_new(); + connections = nm_client_get_connections(nmc->client); + for (i = 0; i < connections->len; i++) { + connection = connections->pdata[i]; + g_ptr_array_add(found_cons, connection); + } + } + + info = g_slice_new0(ConnectionCbInfo); + info->nmc = nmc; + info->obj_list = g_ptr_array_sized_new(found_cons->len); + for (i = 0; i < found_cons->len; i++) { + connection = found_cons->pdata[i]; + g_ptr_array_add(info->obj_list, g_object_ref(connection)); + } + info->timeout_id = g_timeout_add_seconds(nmc->timeout, connection_op_timeout_cb, info); + info->cancellable = g_cancellable_new(); + + nmc->nowait_flag = (nmc->timeout == 0); + nmc->should_wait++; + + for (i = 0; i < found_cons->len; i++) { + nm_remote_connection_update2(NM_REMOTE_CONNECTION(found_cons->pdata[i]), + NULL, + 0, + g_variant_new_parsed("{'plugin': <%s>}", plugin), + info->cancellable, + migrate_cb, + info); + } + +finish: + if (invalid_cons) { + g_string_truncate(invalid_cons, invalid_cons->len - 2); /* truncate trailing ", " */ + g_string_printf(nmc->return_text, + _("Error: cannot migrate unknown connection(s): %s."), + invalid_cons->str); + } +} + static char * gen_func_connection_names(const char *text, int state) { @@ -9693,6 +9913,7 @@ nmc_command_func_connection(const NMCCommand *cmd, NmCli *nmc, int argc, const c {"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}, + {"migrate", do_connection_migrate, usage_connection_migrate, TRUE, TRUE}, {"monitor", do_connection_monitor, usage_connection_monitor, TRUE, TRUE}, {NULL, do_connections_show, usage, TRUE, TRUE}, }; diff --git a/src/nmcli/devices.c b/src/nmcli/devices.c index e23ef681..2bfc4cec 100644 --- a/src/nmcli/devices.c +++ b/src/nmcli/devices.c @@ -1216,12 +1216,30 @@ get_device(NmCli *nmc, int *argc, const char *const **argv, GError **error) return devices[i]; } +static bool +_ap_is_wep(NMAccessPoint *ap) +{ + NM80211ApFlags flags = nm_access_point_get_flags(ap); + NM80211ApSecurityFlags wpa_flags = nm_access_point_get_wpa_flags(ap); + NM80211ApSecurityFlags rsn_flags = nm_access_point_get_rsn_flags(ap); + + if ((flags & NM_802_11_AP_FLAGS_PRIVACY) && (wpa_flags == NM_802_11_AP_SEC_NONE) + && (rsn_flags == NM_802_11_AP_SEC_NONE)) { + return TRUE; + } + + return FALSE; +} + static int compare_aps(gconstpointer a, gconstpointer b, gpointer user_data) { NMAccessPoint *apa = *(NMAccessPoint **) a; NMAccessPoint *apb = *(NMAccessPoint **) b; + /* Sort the deprecated WEP connections last. */ + NM_CMP_DIRECT(_ap_is_wep(apb), _ap_is_wep(apa)); + 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)); @@ -1249,22 +1267,19 @@ sort_access_points(const GPtrArray *aps) } typedef struct { - NmCli *nmc; - int index; - guint32 output_flags; - const char *active_bssid; - const char *device; - GPtrArray *output_data; + NmCli *nmc; + NMAccessPoint *active_ap; + const char *device; + GPtrArray *output_data; + int *p_index; + guint32 output_flags; } APInfo; static void -fill_output_access_point(gpointer data, gpointer user_data) +fill_output_access_point(NMAccessPoint *ap, const APInfo *info) { - NMAccessPoint *ap = NM_ACCESS_POINT(data); - APInfo *info = (APInfo *) user_data; NmcOutputField *arr; - gboolean active = FALSE; - NM80211ApFlags flags; + gboolean active; NM80211ApSecurityFlags wpa_flags, rsn_flags; guint32 freq, bitrate; guint8 strength; @@ -1284,14 +1299,9 @@ fill_output_access_point(gpointer data, gpointer user_data) const char *sig_bars; NMMetaColor color; - if (info->active_bssid) { - const char *current_bssid = nm_access_point_get_bssid(ap); - if (current_bssid && !strcmp(current_bssid, info->active_bssid)) - active = TRUE; - } + active = (info->active_ap == ap); /* Get AP properties */ - flags = nm_access_point_get_flags(ap); wpa_flags = nm_access_point_get_wpa_flags(ap); rsn_flags = nm_access_point_get_rsn_flags(ap); ssid = nm_access_point_get_ssid(ap); @@ -1320,26 +1330,27 @@ fill_output_access_point(gpointer data, gpointer user_data) security_str = g_string_new(NULL); - if ((flags & NM_802_11_AP_FLAGS_PRIVACY) && (wpa_flags == NM_802_11_AP_SEC_NONE) - && (rsn_flags == NM_802_11_AP_SEC_NONE)) { + if (_ap_is_wep(ap)) { g_string_append(security_str, "WEP "); - } - if (wpa_flags != NM_802_11_AP_SEC_NONE) { - g_string_append(security_str, "WPA1 "); - } - if ((rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { - g_string_append(security_str, "WPA2 "); - } - if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) { - g_string_append(security_str, "WPA3 "); - } - if (NM_FLAGS_ANY(rsn_flags, NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) { - 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 "); + } else { + if (wpa_flags != NM_802_11_AP_SEC_NONE) { + g_string_append(security_str, "WPA1 "); + } + if ((rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { + g_string_append(security_str, "WPA2 "); + } + if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) { + g_string_append(security_str, "WPA3 "); + } + if (NM_FLAGS_ANY(rsn_flags, + NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) { + 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 "); + } } if (security_str->len > 0) @@ -1348,7 +1359,7 @@ fill_output_access_point(gpointer data, gpointer user_data) arr = nmc_dup_fields_array((const NMMetaAbstractInfo *const *) nmc_fields_dev_wifi_list, info->output_flags); - ap_name = g_strdup_printf("AP[%d]", info->index++); /* AP */ + ap_name = g_strdup_printf("AP[%d]", ++(*info->p_index)); /* AP */ set_val_str(arr, 0, ap_name); set_val_str(arr, 1, ssid_str); set_val_str(arr, 2, ssid_hex_str); @@ -1374,6 +1385,8 @@ fill_output_access_point(gpointer data, gpointer user_data) /* Set colors */ color = wifi_signal_to_color(strength); + if (_ap_is_wep(ap)) + color = NM_META_COLOR_WIFI_DEPRECATED; set_val_color_all(arr, color); if (active) arr[15].color = NM_META_COLOR_CONNECTION_ACTIVATED; @@ -1381,6 +1394,12 @@ fill_output_access_point(gpointer data, gpointer user_data) g_ptr_array_add(info->output_data, arr); } +static void +fill_output_access_point_void(gpointer data, gpointer user_data) +{ + fill_output_access_point(data, user_data); +} + static char * bluetooth_caps_to_string(NMBluetoothCapabilities caps) { @@ -1679,18 +1698,14 @@ show_device_info(NMDevice *device, NmCli *nmc) /* Wireless specific information */ if ((NM_IS_DEVICE_WIFI(device))) { - NMAccessPoint *active_ap = NULL; - const char *active_bssid = NULL; - /* section AP */ if (!g_ascii_strcasecmp(nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[4]->name)) { + NMAccessPoint *active_ap = NULL; NMC_OUTPUT_DATA_DEFINE_SCOPED(out); - if (state == NM_DEVICE_STATE_ACTIVATED) { - active_ap = nm_device_wifi_get_active_access_point(NM_DEVICE_WIFI(device)); - active_bssid = active_ap ? nm_access_point_get_bssid(active_ap) : NULL; - } + if (state == NM_DEVICE_STATE_ACTIVATED) + active_ap = nm_device_wifi_get_active_access_point(NM_DEVICE_WIFI(device)); tmpl = (const NMMetaAbstractInfo *const *) nmc_fields_dev_wifi_list; out_indices = @@ -1703,19 +1718,20 @@ show_device_info(NMDevice *device, NmCli *nmc) g_ptr_array_add(out.output_data, arr); { - gs_unref_ptrarray GPtrArray *aps = NULL; - APInfo info = { + gs_unref_ptrarray GPtrArray *aps = NULL; + int info_index = 0; + const APInfo info = { .nmc = nmc, - .index = 1, + .p_index = &info_index, .output_flags = NMC_OF_FLAG_SECTION_PREFIX, - .active_bssid = active_bssid, + .active_ap = active_ap, .device = nm_device_get_iface(device), .output_data = out.output_data, }; 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_foreach(aps, fill_output_access_point_void, (gpointer) &info); } print_data_prepare_width(out.output_data); @@ -2991,32 +3007,30 @@ find_ap_on_device(NMDevice *device, const char *bssid, const char *ssid, gboolea static void show_access_point_info(NMDeviceWifi *wifi, NmCli *nmc, NmcOutputData *out) { - NMAccessPoint *active_ap = NULL; - const char *active_bssid = NULL; + NMAccessPoint *active_ap = NULL; NmcOutputField *arr; - if (nm_device_get_state(NM_DEVICE(wifi)) == NM_DEVICE_STATE_ACTIVATED) { - active_ap = nm_device_wifi_get_active_access_point(wifi); - active_bssid = active_ap ? nm_access_point_get_bssid(active_ap) : NULL; - } + if (nm_device_get_state(NM_DEVICE(wifi)) == NM_DEVICE_STATE_ACTIVATED) + active_ap = nm_device_wifi_get_active_access_point(wifi); arr = nmc_dup_fields_array((const NMMetaAbstractInfo *const *) nmc_fields_dev_wifi_list, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); g_ptr_array_add(out->output_data, arr); { - gs_unref_ptrarray GPtrArray *aps = NULL; - APInfo info = { + gs_unref_ptrarray GPtrArray *aps = NULL; + int info_index = 0; + const APInfo info = { .nmc = nmc, - .index = 1, + .p_index = &info_index, .output_flags = 0, - .active_bssid = active_bssid, + .active_ap = active_ap, .device = nm_device_get_iface(NM_DEVICE(wifi)), .output_data = out->output_data, }; aps = sort_access_points(nm_device_wifi_get_access_points(wifi)); - g_ptr_array_foreach(aps, fill_output_access_point, &info); + g_ptr_array_foreach(aps, fill_output_access_point_void, (gpointer) &info); } print_data_prepare_width(out->output_data); @@ -3032,7 +3046,6 @@ wifi_print_aps(NMDeviceWifi *wifi, { NMAccessPoint *ap = NULL; const GPtrArray *aps; - APInfo *info; guint i; NmcOutputField *arr; const char *base_hdr = _("Wi-Fi scan list"); @@ -3061,23 +3074,23 @@ wifi_print_aps(NMDeviceWifi *wifi, ap = candidate_ap; } if (ap) { + int info_index = 0; + const APInfo info = { + .nmc = nmc, + .p_index = &info_index, + .output_flags = 0, + .device = nm_device_get_iface(NM_DEVICE(wifi)), + .output_data = out.output_data, + }; + /* Add headers (field names) */ arr = nmc_dup_fields_array(tmpl, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); g_ptr_array_add(out.output_data, arr); - info = g_malloc0(sizeof(APInfo)); - info->nmc = nmc; - info->index = 1; - info->output_flags = 0; - info->active_bssid = NULL; - info->device = nm_device_get_iface(NM_DEVICE(wifi)); - info->output_data = out.output_data; - - fill_output_access_point(ap, info); + fill_output_access_point(ap, &info); print_data_prepare_width(out.output_data); print_data(&nmc->nmc_config, &nmc->pager_data, out_indices, header_name, 0, &out); - g_free(info); *bssid_found = TRUE; empty_line = TRUE; diff --git a/src/nmcli/general.c b/src/nmcli/general.c index 65437e79..d5a6788f 100644 --- a/src/nmcli/general.c +++ b/src/nmcli/general.c @@ -145,12 +145,22 @@ _metagen_general_status_get_fcn(NMC_META_GENERIC_INFO_GET_FCN_ARGS) v_bool = nm_client_networking_get_enabled(nmc->client); goto enabled_out; case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI_HW: + if (!(nm_client_get_radio_flags(nmc->client) & NM_RADIO_FLAG_WLAN_AVAILABLE)) { + NMC_HANDLE_COLOR(NM_META_COLOR_NONE); + value = N_("missing"); + goto translate_and_out; + } v_bool = nm_client_wireless_hardware_get_enabled(nmc->client); goto enabled_out; case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WIFI: v_bool = nm_client_wireless_get_enabled(nmc->client); goto enabled_out; case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN_HW: + if (!(nm_client_get_radio_flags(nmc->client) & NM_RADIO_FLAG_WWAN_AVAILABLE)) { + NMC_HANDLE_COLOR(NM_META_COLOR_NONE); + value = N_("missing"); + goto translate_and_out; + } v_bool = nm_client_wwan_hardware_get_enabled(nmc->client); goto enabled_out; case NMC_GENERIC_INFO_TYPE_GENERAL_STATUS_WWAN: diff --git a/src/nmcli/generate-docs-nm-settings-nmcli.xml b/src/nmcli/generate-docs-nm-settings-nmcli.xml index 1d329305..525b36b6 100644 --- a/src/nmcli/generate-docs-nm-settings-nmcli.xml +++ b/src/nmcli/generate-docs-nm-settings-nmcli.xml @@ -371,7 +371,7 @@ + description="This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The '$' character is treated special to perform dynamic substitutions at runtime. Currently, supported are "${CONNECTION}", "${DEVICE}", "${MAC}", "${BOOT}", "${RANDOM}". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that "${DEVICE}" corresponds to the interface name of the device and "${MAC}" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as "$$". For example, set it to "${CONNECTION}-${BOOT}-${DEVICE}" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to "${CONNECTION}" and uses a unique, fixed ID for the connection." /> @@ -380,7 +380,7 @@ description="The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface." /> + description="Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection. Autoconnect happens when the circumstances are suitable. That means for example that the device is currently managed and not active. Autoconnect thus never replaces or competes with an already active profile. Note that autoconnect is not implemented for VPN profiles. See "secondaries" as an alternative to automatically connect VPN profiles. If multiple profiles are ready to autoconnect on the same device, the one with the better "connection.autoconnect-priority" is chosen. If the priorities are equal, then the most recently connected profile is activated. If the profiles were not connected earlier or their "connection.timestamp" is identical, the choice is undefined. Depending on "connection.multi-connect", a profile can (auto)connect only once at a time or multiple times." /> + description="A list of IPv6 addresses and their prefix length. Multiple addresses can be separated by comma. For example "2001:db8:85a3::8a2e:370:7334/64, 2001:db8:85a3::5/64". The addresses are listed in decreasing priority, meaning the first address will be the primary address. This can make a difference with IPv6 source address selection (RFC 6724, section 5)." /> @@ -911,7 +911,7 @@ description="PAC URL for obtaining PAC file." /> + description="The PAC script. In the profile this must be an UTF-8 encoded javascript code that defines a FindProxyForURL() function. When setting the property in nmcli, a filename is accepted too. In that case, nmcli will read the content of the file and set the script. The prefixes "file://" and "js://" are supported to explicitly differentiate between the two." /> + description="This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The '$' character is treated special to perform dynamic substitutions at runtime. Currently, supported are "${CONNECTION}", "${DEVICE}", "${MAC}", "${BOOT}", "${RANDOM}". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that "${DEVICE}" corresponds to the interface name of the device and "${MAC}" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as "$$". For example, set it to "${CONNECTION}-${BOOT}-${DEVICE}" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to "${CONNECTION}" and uses a unique, fixed ID for the connection." /> @@ -380,7 +380,7 @@ description="The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface." /> + description="Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection. Autoconnect happens when the circumstances are suitable. That means for example that the device is currently managed and not active. Autoconnect thus never replaces or competes with an already active profile. Note that autoconnect is not implemented for VPN profiles. See "secondaries" as an alternative to automatically connect VPN profiles. If multiple profiles are ready to autoconnect on the same device, the one with the better "connection.autoconnect-priority" is chosen. If the priorities are equal, then the most recently connected profile is activated. If the profiles were not connected earlier or their "connection.timestamp" is identical, the choice is undefined. Depending on "connection.multi-connect", a profile can (auto)connect only once at a time or multiple times." /> + description="A list of IPv6 addresses and their prefix length. Multiple addresses can be separated by comma. For example "2001:db8:85a3::8a2e:370:7334/64, 2001:db8:85a3::5/64". The addresses are listed in decreasing priority, meaning the first address will be the primary address. This can make a difference with IPv6 source address selection (RFC 6724, section 5)." /> @@ -911,7 +911,7 @@ description="PAC URL for obtaining PAC file." /> + description="The PAC script. In the profile this must be an UTF-8 encoded javascript code that defines a FindProxyForURL() function. When setting the property in nmcli, a filename is accepted too. In that case, nmcli will read the content of the file and set the script. The prefixes "file://" and "js://" are supported to explicitly differentiate between the two." /> #include #include -#include #include #include #if HAVE_EDITLINE_READLINE @@ -44,6 +43,7 @@ [NM_META_COLOR_CONNECTION_DISCONNECTING] = "31", \ [NM_META_COLOR_CONNECTION_INVISIBLE] = "2", \ [NM_META_COLOR_CONNECTION_EXTERNAL] = "32;2", \ + [NM_META_COLOR_CONNECTION_DEPRECATED] = "2", \ [NM_META_COLOR_CONNECTIVITY_FULL] = "32", \ [NM_META_COLOR_CONNECTIVITY_LIMITED] = "33", \ [NM_META_COLOR_CONNECTIVITY_NONE] = "31", \ @@ -74,6 +74,7 @@ [NM_META_COLOR_WIFI_SIGNAL_GOOD] = "33", \ [NM_META_COLOR_WIFI_SIGNAL_POOR] = "36", \ [NM_META_COLOR_WIFI_SIGNAL_UNKNOWN] = "2", \ + [NM_META_COLOR_WIFI_DEPRECATED] = "2", \ [NM_META_COLOR_ENABLED] = "32", \ [NM_META_COLOR_DISABLED] = "31", \ }, \ @@ -118,8 +119,7 @@ typedef struct { } ArgsInfo; /* --- Global variables --- */ -GMainLoop *loop = NULL; -struct termios termios_orig; +GMainLoop *loop = NULL; NM_CACHED_QUARK_FCN("nmcli-error-quark", nmcli_error_quark); @@ -551,6 +551,7 @@ static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( {"connection-external", NM_META_COLOR_CONNECTION_EXTERNAL}, {"connection-invisible", NM_META_COLOR_CONNECTION_INVISIBLE}, {"connection-unknown", NM_META_COLOR_CONNECTION_UNKNOWN}, + {"connection-deprecated", NM_META_COLOR_CONNECTION_DEPRECATED}, {"connectivity-full", NM_META_COLOR_CONNECTIVITY_FULL}, {"connectivity-limited", NM_META_COLOR_CONNECTIVITY_LIMITED}, {"connectivity-none", NM_META_COLOR_CONNECTIVITY_NONE}, @@ -587,7 +588,8 @@ static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( {"wifi-signal-fair", NM_META_COLOR_WIFI_SIGNAL_FAIR}, {"wifi-signal-good", NM_META_COLOR_WIFI_SIGNAL_GOOD}, {"wifi-signal-poor", NM_META_COLOR_WIFI_SIGNAL_POOR}, - {"wifi-signal-unknown", NM_META_COLOR_WIFI_SIGNAL_UNKNOWN}, ); + {"wifi-signal-unknown", NM_META_COLOR_WIFI_SIGNAL_UNKNOWN}, + {"wifi-deprecated", NM_META_COLOR_WIFI_DEPRECATED}, ); static gboolean parse_color_scheme(char *palette_buffer, NmcColorPalette *out_palette, GError **error) @@ -935,7 +937,6 @@ nmc_clear_sigint(void) void nmc_exit(void) { - tcsetattr(STDIN_FILENO, TCSADRAIN, &termios_orig); nmc_cleanup_readline(); exit(1); } @@ -1026,9 +1027,6 @@ main(int argc, char *argv[]) textdomain(GETTEXT_PACKAGE); #endif - /* Save terminal settings */ - tcgetattr(STDIN_FILENO, &termios_orig); - nm_cli.return_text = g_string_new(_("Success")); loop = g_main_loop_new(NULL, FALSE); diff --git a/src/nmcli/utils.c b/src/nmcli/utils.c index 7645a08c..209a5b69 100644 --- a/src/nmcli/utils.c +++ b/src/nmcli/utils.c @@ -156,7 +156,7 @@ next_arg(NmCli *nmc, int *argc, const char *const **argv, ...) va_list args; const char *cmd_option; - g_assert(*argc >= 0); + g_return_val_if_fail(*argc >= 0, -1); do { int cmd_option_pos = 1; @@ -1229,7 +1229,7 @@ _print_do(const NmcConfig *nmc_config, guint i_row, i_col; nm_auto_free_gstring GString *str = NULL; - g_assert(col_len); + g_return_if_fail(col_len); /* Main header */ if (nmc_config->print_output == NMC_PRINT_PRETTY && header_name_no_l10n) { @@ -1628,7 +1628,7 @@ print_required_fields(const NmcConfig *nmc_config, gboolean is_array = field_values[idx].value_is_array; /* section prefix can't be an array */ - g_assert(!is_array || !section_prefix || idx != 0); + g_return_if_fail(!is_array || !section_prefix || idx != 0); if (section_prefix && idx == 0) /* The first field is section prefix */ continue; -- cgit 1.3.0-6-gf8a5