device,cli: merge branch 'th/reapply-fixes-bgo765848'

https://bugzilla.gnome.org/show_bug.cgi?id=765848

(cherry picked from commit f5ae41656a)
This commit is contained in:
Thomas Haller 2016-05-03 11:55:52 +02:00
commit acf9bad08a
10 changed files with 75 additions and 199 deletions

View file

@ -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)
{

View file

@ -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

View file

@ -286,7 +286,7 @@ usage (void)
" show [<ifname>]\n\n"
" set [ifname] <ifname> [autoconnect yes|no] [managed yes|no]\n\n"
" connect <ifname>\n\n"
" reapply <ifname> ...\n\n"
" reapply <ifname>\n\n"
" disconnect <ifname> ...\n\n"
" delete <ifname> ...\n\n"
" monitor <ifname> ...\n\n"
@ -342,7 +342,7 @@ usage_device_reapply (void)
{
g_printerr (_("Usage: nmcli device reapply { ARGUMENTS | help }\n"
"\n"
"ARGUMENTS := <ifname> ...\n"
"ARGUMENTS := <ifname>\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)
{

View file

@ -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)

View file

@ -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 */

View file

@ -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)
{

View file

@ -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 <ESC>[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, ]"

View file

@ -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);

View file

@ -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;
}

View file

@ -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 ? : "<UNKNOWN>");
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;