diff --git a/clients/cli/common.c b/clients/cli/common.c index 0aa5efc260..0888f0630c 100644 --- a/clients/cli/common.c +++ b/clients/cli/common.c @@ -1170,10 +1170,6 @@ nmc_set_in_readline (gboolean in_readline) pthread_mutex_unlock (&readline_mutex); } -/* Global variable defined in nmcli.c */ -extern NmCli nm_cli; - - static char * nmc_readline_helper (const char *prompt) { diff --git a/clients/cli/connections.c b/clients/cli/connections.c index d01e38efba..1f1dae5981 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -261,9 +261,6 @@ typedef struct { } TabCompletionInfo; static TabCompletionInfo nmc_tab_completion = {NULL, NULL, NULL, NULL}; -/* Global variable defined in nmcli.c - used for TAB completion */ -extern NmCli nm_cli; - static char *gen_connection_types (const char *text, int state); static void diff --git a/clients/cli/devices.c b/clients/cli/devices.c index ec8d235b9c..65c4be7286 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -286,7 +286,7 @@ usage (void) " show []\n\n" " set [ifname] [autoconnect yes|no] [managed yes|no]\n\n" " connect \n\n" - " reapply ...\n\n" + " reapply \n\n" " disconnect ...\n\n" " delete ...\n\n" " monitor ...\n\n" @@ -342,7 +342,7 @@ usage_device_reapply (void) { g_printerr (_("Usage: nmcli device reapply { ARGUMENTS | help }\n" "\n" - "ARGUMENTS := ...\n" + "ARGUMENTS := \n" "\n" "Attempts to update device with changes to the currently active connection\n" "made since it was last applied.\n\n")); @@ -1835,11 +1835,10 @@ reapply_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) GError *error = NULL; if (!nm_device_reapply_finish (device, result, &error)) { - g_string_printf (nmc->return_text, _("Error: not all connections reapplied.")); - g_printerr (_("Error: Reapplying connection to device '%s' (%s) failed: %s\n"), - nm_device_get_iface (device), - nm_object_get_path (NM_OBJECT (device)), - error->message); + g_string_printf (nmc->return_text, _("Error: Reapplying connection to device '%s' (%s) failed: %s"), + nm_device_get_iface (device), + nm_object_get_path (NM_OBJECT (device)), + error->message); g_error_free (error); nmc->return_value = NMC_RESULT_ERROR_DEV_DISCONNECT; device_cb_info_finish (info, device); @@ -1847,7 +1846,7 @@ reapply_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) if (nmc->print_output == NMC_PRINT_PRETTY) nmc_terminal_erase_line (); g_print (_("Connection successfully reapplied to device '%s'.\n"), - nm_device_get_iface (device)); + nm_device_get_iface (device)); device_cb_info_finish (info, device); } } @@ -1855,14 +1854,14 @@ reapply_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) static NMCResultCode do_device_reapply (NmCli *nmc, int argc, char **argv) { - NMDevice **devices; - NMDevice *device; + gs_free NMDevice **devices = NULL; + NMDevice *device = NULL; DeviceCbInfo *info = NULL; - GSList *queue = NULL, *iter; - char **arg_arr = NULL; char **arg_ptr = argv; int arg_num = argc; int i; + gs_free char *device_name_free = NULL; + const char *device_name = NULL; /* Set default timeout for reapply operation. */ if (nmc->timeout == -1) @@ -1870,69 +1869,48 @@ do_device_reapply (NmCli *nmc, int argc, char **argv) if (argc == 0) { if (nmc->ask) { - char *line = nmc_readline (PROMPT_INTERFACES); - nmc_string_to_arg_array (line, NULL, FALSE, &arg_arr, &arg_num); - g_free (line); - arg_ptr = arg_arr; + device_name_free = nmc_readline (PROMPT_INTERFACE); + device_name = device_name_free; } - if (arg_num == 0) { + if (!device_name) { g_string_printf (nmc->return_text, _("Error: No interface specified.")); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + return nmc->return_value; } + } else if (argc == 1) { + device_name = arg_ptr[0]; + next_arg (&arg_num, &arg_ptr); + } else { + next_arg (&arg_num, &arg_ptr); + g_string_printf (nmc->return_text, _("Error: unsupported argument '%s'."), *arg_ptr); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return nmc->return_value; } devices = get_devices_sorted (nmc->client); - while (arg_num > 0) { - device = NULL; - for (i = 0; devices[i]; i++) { - if (!g_strcmp0 (nm_device_get_iface (devices[i]), *arg_ptr)) { - device = devices[i]; - break; - } + for (i = 0; devices[i]; i++) { + if (!g_strcmp0 (nm_device_get_iface (devices[i]), device_name)) { + device = devices[i]; + break; } - - if (device) { - if (!g_slist_find (queue, device)) - queue = g_slist_prepend (queue, device); - else - g_printerr (_("Warning: argument '%s' is duplicated.\n"), *arg_ptr); - } else { - g_printerr (_("Error: Device '%s' not found.\n"), *arg_ptr); - g_string_printf (nmc->return_text, _("Error: not all devices found.")); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - } - - /* Take next argument */ - next_arg (&arg_num, &arg_ptr); } - g_free (devices); - if (!queue) { - g_string_printf (nmc->return_text, _("Error: no valid device provided.")); + if (!device) { + g_string_printf (nmc->return_text, _("Error: device '%s' not found."), device_name); nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; + return nmc->return_value; } - queue = g_slist_reverse (queue); - - info = g_slice_new0 (DeviceCbInfo); - info->nmc = nmc; nmc->nowait_flag = (nmc->timeout == 0); nmc->should_wait = TRUE; - for (iter = queue; iter; iter = g_slist_next (iter)) { - device = iter->data; + info = g_slice_new0 (DeviceCbInfo); + info->nmc = nmc; + info->queue = g_slist_prepend (info->queue, g_object_ref (device)); - info->queue = g_slist_prepend (info->queue, g_object_ref (device)); + /* Now reapply the connection to the device */ + nm_device_reapply_async (device, NULL, 0, 0, NULL, reapply_device_cb, info); - /* Now reapply the connection to the device */ - nm_device_reapply_async (device, NULL, 0, 0, NULL, reapply_device_cb, info); - } - -error: - g_strfreev (arg_arr); - g_slist_free (queue); return nmc->return_value; } @@ -3594,9 +3572,6 @@ is_single_word (const char* line) return FALSE; } -/* Global variable defined in nmcli.c */ -extern NmCli nm_cli; - static char * gen_func_ifnames (const char *text, int state) { diff --git a/clients/cli/nmcli-completion b/clients/cli/nmcli-completion index 1b1dce3322..3c87f6f9d4 100644 --- a/clients/cli/nmcli-completion +++ b/clients/cli/nmcli-completion @@ -1425,12 +1425,12 @@ _nmcli() fi ;; sh|sho|show| \ + r|re|rea|reap|reapp|reappl|reapply| \ c|co|con|conn|conne|connec|connect) if [[ ${#words[@]} -eq 3 ]]; then _nmcli_compl_COMMAND_nl "${words[2]}" "$(_nmcli_dev_status DEVICE)" fi ;; - r|re|rea|reap|reapp|reappl|reapply| \ d|di|dis|disc|disco|discon|disconn|disconne|disconnec|disconnect| \ de|del|dele|delet|delete| \ m|mo|mon|moni|monit|monito|monitor) diff --git a/clients/cli/nmcli.h b/clients/cli/nmcli.h index 9048a69f7e..34100f0026 100644 --- a/clients/cli/nmcli.h +++ b/clients/cli/nmcli.h @@ -161,6 +161,8 @@ typedef struct _NmCli { NmcTermColor editor_prompt_color; /* Color of prompt in connection editor */ } NmCli; +extern NmCli nm_cli; + /* Error quark for GError domain */ #define NMCLI_ERROR (nmcli_error_quark ()) GQuark nmcli_error_quark (void); @@ -169,5 +171,4 @@ gboolean nmc_seen_sigint (void); void nmc_clear_sigint (void); void nmc_set_sigquit_internal (void); - #endif /* NMC_NMCLI_H */ diff --git a/clients/cli/settings.c b/clients/cli/settings.c index 06e9fb4722..1651aab226 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -2082,13 +2082,6 @@ typedef struct { NmcPropertyFuncsFields } NmcPropertyFuncs; -/* - * We need NmCli in some _set_property functions, and they aren't passed NmCli. - * So use the global variable. - */ -/* Global variable defined in nmcli.c */ -extern NmCli nm_cli; - NMSetting * nmc_setting_new_for_name (const char *name) { diff --git a/clients/cli/utils.c b/clients/cli/utils.c index 87b37bb1a5..a406eee459 100644 --- a/clients/cli/utils.c +++ b/clients/cli/utils.c @@ -181,60 +181,6 @@ ssid_to_hex (const char *str, gsize len) return printable_str; } -/* - * Converts IPv4 address from guint32 in network-byte order to text representation. - * Returns: text form of the IP or NULL (then error is set) - */ -char * -nmc_ip4_address_as_string (guint32 ip, GError **error) -{ - guint32 tmp_addr; - char buf[INET_ADDRSTRLEN]; - - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - memset (&buf, '\0', sizeof (buf)); - tmp_addr = ip; - - if (inet_ntop (AF_INET, &tmp_addr, buf, INET_ADDRSTRLEN)) { - return g_strdup (buf); - } else { - g_set_error (error, NMCLI_ERROR, 0, _("Error converting IP4 address '0x%X' to text form"), - ntohl (tmp_addr)); - return NULL; - } -} - -/* - * Converts IPv6 address in in6_addr structure to text representation. - * Returns: text form of the IP or NULL (then error is set) - */ -char * -nmc_ip6_address_as_string (const struct in6_addr *ip, GError **error) -{ - char buf[INET6_ADDRSTRLEN]; - - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - memset (&buf, '\0', sizeof (buf)); - - if (inet_ntop (AF_INET6, ip, buf, INET6_ADDRSTRLEN)) { - return g_strdup (buf); - } else { - if (error) { - int j; - GString *ip6_str = g_string_new (NULL); - g_string_append_printf (ip6_str, "%02X", ip->s6_addr[0]); - for (j = 1; j < 16; j++) - g_string_append_printf (ip6_str, " %02X", ip->s6_addr[j]); - g_set_error (error, NMCLI_ERROR, 0, _("Error converting IP6 address '%s' to text form"), - ip6_str->str); - g_string_free (ip6_str, TRUE); - } - return NULL; - } -} - /* * Erase terminal line using ANSI escape sequences. * It prints [2K sequence to erase the line and then \r to return back @@ -706,23 +652,6 @@ finish: return ret; } -/* - * Convert string array (char **) to GSList. - * - * Returns: pointer to newly created GSList. Caller should free it. - */ -GSList * -nmc_util_strv_to_slist (char **strv) -{ - GSList *list = NULL; - guint i = 0; - - while (strv && strv[i]) - list = g_slist_prepend (list, g_strdup (strv[i++])); - - return g_slist_reverse (list); -} - /* * Convert string array (char **) to description string in the form of: * "[string1, string2, ]" diff --git a/clients/cli/utils.h b/clients/cli/utils.h index 224acb0cb3..eab60d3a10 100644 --- a/clients/cli/utils.h +++ b/clients/cli/utils.h @@ -69,8 +69,6 @@ gboolean nmc_string_to_uint (const char *str, unsigned long int *value); gboolean nmc_string_to_bool (const char *str, gboolean *val_bool, GError **error); gboolean nmc_string_to_tristate (const char *str, NMCTriStateValue *val, GError **error); -char *nmc_ip4_address_as_string (guint32 ip, GError **error); -char *nmc_ip6_address_as_string (const struct in6_addr *ip, GError **error); void nmc_terminal_erase_line (void); void nmc_terminal_show_progress (const char *str); const char *nmc_term_color_sequence (NmcTermColor color); @@ -83,7 +81,6 @@ char *nmc_get_user_input (const char *ask_str); int nmc_string_to_arg_array (const char *line, const char *delim, gboolean unquote, char ***argv, int *argc); const char *nmc_string_is_valid (const char *input, const char **allowed, GError **error); -GSList *nmc_util_strv_to_slist (char **strv); char * nmc_util_strv_for_display (const char **strv, gboolean brackets); char **nmc_strsplit_set (const char *str, const char *delimiter, int max_tokens); int nmc_string_screen_width (const char *start, const char *end); diff --git a/shared/nm-shared-utils.c b/shared/nm-shared-utils.c index 932b7432c3..38f6529d2a 100644 --- a/shared/nm-shared-utils.c +++ b/shared/nm-shared-utils.c @@ -45,8 +45,7 @@ gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback) { gint64 v; - size_t len; - char buf[64], *s, *str_free = NULL; + char *s = NULL; if (str) { while (g_ascii_isspace (str[0])) @@ -57,46 +56,24 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma return fallback; } - len = strlen (str); - if (g_ascii_isspace (str[--len])) { - /* backward search the first non-ws character. - * We already know that str[0] is non-ws. */ - while (g_ascii_isspace (str[--len])) - ; - - /* str[len] is now the last non-ws character... */ - len++; - - if (len >= sizeof (buf)) - s = str_free = g_malloc (len + 1); - else - s = buf; - - memcpy (s, str, len); - s[len] = 0; - - nm_assert (len > 0 && len < strlen (str) && len == strlen (s)); - nm_assert (!g_ascii_isspace (str[len-1]) && g_ascii_isspace (str[len])); - nm_assert (strncmp (str, s, len) == 0); - - str = s; - } - errno = 0; v = g_ascii_strtoll (str, &s, base); if (errno != 0) - v = fallback; - else if (s[0] != 0) { - errno = EINVAL; - v = fallback; - } else if (v > max || v < min) { + return fallback; + if (s[0] != '\0') { + while (g_ascii_isspace (s[0])) + s++; + if (s[0] != '\0') { + errno = EINVAL; + return fallback; + } + } + if (v > max || v < min) { errno = ERANGE; - v = fallback; + return fallback; } - if (G_UNLIKELY (str_free)) - g_free (str_free); return v; } diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 692ffa7ba4..226e8f5970 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -7178,22 +7178,25 @@ _hash_check_invalid_keys_impl (GHashTable *hash, const char *setting_name, GErro g_hash_table_iter_init (&iter, hash); while (g_hash_table_iter_next (&iter, (gpointer *) &k, NULL)) { - for (i = 0; argv[i]; i++) { - if (!strcmp (argv[i], k)) { - first_invalid_key = k; - break; - } - } - if (first_invalid_key) + if (_nm_utils_strv_find_first ((char **) argv, -1, k) < 0) { + first_invalid_key = k; break; + } + } + if (setting_name) { + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + "Can't reapply changes to '%s.%s' setting", + setting_name, + first_invalid_key); + } else { + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + "Can't reapply any changes to '%s' setting", + first_invalid_key); } - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Can't reapply changes to '%s%s%s' setting", - setting_name ? : "", - setting_name ? "." : "", - first_invalid_key ? : ""); g_return_val_if_fail (first_invalid_key, FALSE); return FALSE; } @@ -7314,9 +7317,16 @@ reapply_connection (NMDevice *self, NM_SETTING_CONNECTION_SETTING_NAME)) return FALSE; + /* whitelist allowed properties from "connection" setting which are allowed to differ. + * + * This includes UUID, there is no principal problem with reapplying a connection + * and changing it's UUID. In fact, disallowing it makes it cumbersome for the user + * to reapply any connection but the original settings-connection. */ if (!_hash_check_invalid_keys (diffs ? g_hash_table_lookup (diffs, NM_SETTING_CONNECTION_SETTING_NAME) : NULL, NM_SETTING_CONNECTION_SETTING_NAME, error, + NM_SETTING_CONNECTION_ID, + NM_SETTING_CONNECTION_UUID, NM_SETTING_CONNECTION_ZONE, NM_SETTING_CONNECTION_METERED)) return FALSE; @@ -7345,6 +7355,7 @@ reapply_connection (NMDevice *self, con_old = applied_clone = nm_simple_connection_new_clone (applied); con_new = applied; nm_connection_replace_settings_from_connection (applied, connection); + nm_connection_clear_secrets (applied); } else con_old = con_new = applied;