diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2016-10-14 11:46:47 +0200 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2016-10-14 11:46:47 +0200 |
commit | b54b47ac70e1d6eb451a902c36db930a6351a5bb (patch) | |
tree | 6833ae7c8c98e360f4f914ac34bdb44ff85bb864 | |
parent | a5f3e6e82f0f3d80ed8a1e191c9ffc219222243f (diff) | |
parent | ce6801d965b7c13c745f4ed0136457e30b84a4e0 (diff) | |
download | network-manager-applet-b54b47ac70e1d6eb451a902c36db930a6351a5bb.tar.gz |
merge: branch 'bg/editor-route-metric-default-bgo769015'
https://bugzilla.gnome.org/show_bug.cgi?id=769015
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | shared/Makefile.am | 2 | ||||
-rw-r--r-- | shared/nm-utils/nm-shared-utils.c | 239 | ||||
-rw-r--r-- | shared/nm-utils/nm-shared-utils.h | 66 | ||||
-rw-r--r-- | src/connection-editor/ip4-routes-dialog.c | 160 | ||||
-rw-r--r-- | src/connection-editor/ip6-routes-dialog.c | 101 | ||||
-rw-r--r-- | src/utils/Makefile.am | 11 | ||||
-rw-r--r-- | src/utils/utils.c | 134 | ||||
-rw-r--r-- | src/utils/utils.h | 24 |
9 files changed, 538 insertions, 201 deletions
diff --git a/configure.ac b/configure.ac index c867681d..e021a2e7 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ AC_INIT([nm-applet], AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([1.11 subdir-objects no-dist-gzip dist-xz -Wno-portability]) +AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz -Wno-portability]) AM_MAINTAINER_MODE([enable]) AM_SILENT_RULES([yes]) diff --git a/shared/Makefile.am b/shared/Makefile.am index d8df46d6..6cc2ad80 100644 --- a/shared/Makefile.am +++ b/shared/Makefile.am @@ -2,6 +2,8 @@ EXTRA_DIST = \ nm-utils/gsystem-local-alloc.h \ nm-utils/nm-glib.h \ nm-utils/nm-macros-internal.h \ + nm-utils/nm-shared-utils.c \ + nm-utils/nm-shared-utils.h \ nm-utils/nm-test-utils.h \ nm-utils/nm-vpn-editor-plugin-call.h \ nm-default.h \ diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c new file mode 100644 index 00000000..38f6529d --- /dev/null +++ b/shared/nm-utils/nm-shared-utils.c @@ -0,0 +1,239 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2016 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-shared-utils.h" + +#include <errno.h> + +/*****************************************************************************/ + +/* _nm_utils_ascii_str_to_int64: + * + * A wrapper for g_ascii_strtoll, that checks whether the whole string + * can be successfully converted to a number and is within a given + * range. On any error, @fallback will be returned and %errno will be set + * to a non-zero value. On success, %errno will be set to zero, check %errno + * for errors. Any trailing or leading (ascii) white space is ignored and the + * functions is locale independent. + * + * The function is guaranteed to return a value between @min and @max + * (inclusive) or @fallback. Also, the parsing is rather strict, it does + * not allow for any unrecognized characters, except leading and trailing + * white space. + **/ +gint64 +_nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback) +{ + gint64 v; + char *s = NULL; + + if (str) { + while (g_ascii_isspace (str[0])) + str++; + } + if (!str || !str[0]) { + errno = EINVAL; + return fallback; + } + + errno = 0; + v = g_ascii_strtoll (str, &s, base); + + if (errno != 0) + 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; + return fallback; + } + + return v; +} + +/*****************************************************************************/ + +gint +_nm_utils_ascii_str_to_bool (const char *str, + gint default_value) +{ + gsize len; + char *s = NULL; + + if (!str) + return default_value; + + while (str[0] && g_ascii_isspace (str[0])) + str++; + + if (!str[0]) + return default_value; + + len = strlen (str); + if (g_ascii_isspace (str[len - 1])) { + s = g_strdup (str); + g_strchomp (s); + str = s; + } + + if (!g_ascii_strcasecmp (str, "true") || !g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "on") || !g_ascii_strcasecmp (str, "1")) + default_value = TRUE; + else if (!g_ascii_strcasecmp (str, "false") || !g_ascii_strcasecmp (str, "no") || !g_ascii_strcasecmp (str, "off") || !g_ascii_strcasecmp (str, "0")) + default_value = FALSE; + if (s) + g_free (s); + return default_value; +} + +/*****************************************************************************/ + +G_DEFINE_QUARK (nm-utils-error-quark, nm_utils_error) + +void +nm_utils_error_set_cancelled (GError **error, + gboolean is_disposing, + const char *instance_name) +{ + if (is_disposing) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING, + "Disposing %s instance", + instance_name && *instance_name ? instance_name : "source"); + } else { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, + "Request cancelled"); + } +} + +gboolean +nm_utils_error_is_cancelled (GError *error, + gboolean consider_is_disposing) +{ + if (error) { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return TRUE; + if ( consider_is_disposing + && g_error_matches (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) + return TRUE; + } + return FALSE; +} + +/*****************************************************************************/ + +/** + * nm_g_object_set_property: + * @object: the target object + * @property_name: the property name + * @value: the #GValue to set + * @error: (allow-none): optional error argument + * + * A reimplementation of g_object_set_property(), but instead + * returning an error instead of logging a warning. All g_object_set*() + * versions in glib require you to not pass invalid types or they will + * log a g_warning() -- without reporting an error. We don't want that, + * so we need to hack error checking around it. + * + * Returns: whether the value was successfully set. + */ +gboolean +nm_g_object_set_property (GObject *object, + const gchar *property_name, + const GValue *value, + GError **error) +{ + GParamSpec *pspec; + nm_auto_unset_gvalue GValue tmp_value = G_VALUE_INIT; + GObjectClass *klass; + + g_return_val_if_fail (G_IS_OBJECT (object), FALSE); + g_return_val_if_fail (property_name != NULL, FALSE); + g_return_val_if_fail (G_IS_VALUE (value), FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + + /* g_object_class_find_property() does g_param_spec_get_redirect_target(), + * where we differ from a plain g_object_set_property(). */ + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name); + + if (!pspec) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + _("object class '%s' has no property named '%s'"), + G_OBJECT_TYPE_NAME (object), + property_name); + return FALSE; + } + if (!(pspec->flags & G_PARAM_WRITABLE)) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + _("property '%s' of object class '%s' is not writable"), + pspec->name, + G_OBJECT_TYPE_NAME (object)); + return FALSE; + } + if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY)) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + _("construct property \"%s\" for object '%s' can't be set after construction"), + pspec->name, G_OBJECT_TYPE_NAME (object)); + return FALSE; + } + + klass = g_type_class_peek (pspec->owner_type); + if (klass == NULL) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + _("'%s::%s' is not a valid property name; '%s' is not a GObject subtype"), + g_type_name (pspec->owner_type), pspec->name, g_type_name (pspec->owner_type)); + return FALSE; + } + + /* provide a copy to work from, convert (if necessary) and validate */ + g_value_init (&tmp_value, pspec->value_type); + if (!g_value_transform (value, &tmp_value)) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + _("unable to set property '%s' of type '%s' from value of type '%s'"), + pspec->name, + g_type_name (pspec->value_type), + G_VALUE_TYPE_NAME (value)); + return FALSE; + } + if ( g_param_value_validate (pspec, &tmp_value) + && !(pspec->flags & G_PARAM_LAX_VALIDATION)) { + gs_free char *contents = g_strdup_value_contents (value); + + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + _("value \"%s\" of type '%s' is invalid or out of range for property '%s' of type '%s'"), + contents, + G_VALUE_TYPE_NAME (value), + pspec->name, + g_type_name (pspec->value_type)); + return FALSE; + } + + g_object_set_property (object, property_name, &tmp_value); + return TRUE; +} + +/*****************************************************************************/ diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h new file mode 100644 index 00000000..f77fb0e3 --- /dev/null +++ b/shared/nm-utils/nm-shared-utils.h @@ -0,0 +1,66 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2016 Red Hat, Inc. + */ + +#ifndef __NM_SHARED_UTILS_H__ +#define __NM_SHARED_UTILS_H__ + +/*****************************************************************************/ + +gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback); + +gint _nm_utils_ascii_str_to_bool (const char *str, + gint default_value); + +/*****************************************************************************/ + +/** + * NMUtilsError: + * @NM_UTILS_ERROR_UNKNOWN: unknown or unclassified error + * @NM_UTILS_ERROR_CANCELLED_DISPOSING: when disposing an object that has + * pending aynchronous operations, the operation is cancelled with this + * error reason. Depending on the usage, this might indicate a bug because + * usually the target object should stay alive as long as there are pending + * operations. + */ +typedef enum { + NM_UTILS_ERROR_UNKNOWN = 0, /*< nick=Unknown >*/ + NM_UTILS_ERROR_CANCELLED_DISPOSING, /*< nick=CancelledDisposing >*/ +} NMUtilsError; + +#define NM_UTILS_ERROR (nm_utils_error_quark ()) +GQuark nm_utils_error_quark (void); + +void nm_utils_error_set_cancelled (GError **error, + gboolean is_disposing, + const char *instance_name); +gboolean nm_utils_error_is_cancelled (GError *error, + gboolean consider_is_disposing); + +/*****************************************************************************/ + +gboolean nm_g_object_set_property (GObject *object, + const gchar *property_name, + const GValue *value, + GError **error); + +/*****************************************************************************/ + +#endif /* __NM_SHARED_UTILS_H__ */ diff --git a/src/connection-editor/ip4-routes-dialog.c b/src/connection-editor/ip4-routes-dialog.c index e4d9b2ea..edb225ee 100644 --- a/src/connection-editor/ip4-routes-dialog.c +++ b/src/connection-editor/ip4-routes-dialog.c @@ -47,121 +47,6 @@ static char *last_edited = NULL; /* cell text */ static char *last_path = NULL; /* row in treeview */ static int last_column = -1; /* column in treeview */ -static gboolean -get_one_int (GtkTreeModel *model, - GtkTreeIter *iter, - int column, - guint32 max_value, - gboolean fail_if_missing, - guint32 *out, - char **out_raw) -{ - char *item = NULL; - gboolean success = FALSE; - long int tmp_int; - - gtk_tree_model_get (model, iter, column, &item, -1); - if (out_raw) - *out_raw = item; - if (!item || !strlen (item)) { - if (!out_raw) - g_free (item); - return fail_if_missing ? FALSE : TRUE; - } - - errno = 0; - tmp_int = strtol (item, NULL, 10); - if (errno || tmp_int < 0 || tmp_int > max_value) - goto out; - - *out = (guint32) tmp_int; - success = TRUE; - -out: - if (!out_raw) - g_free (item); - return success; -} - -static gboolean -get_one_prefix (GtkTreeModel *model, - GtkTreeIter *iter, - int column, - gboolean fail_if_missing, - guint32 *out, - char **out_raw) -{ - char *item = NULL; - struct in_addr tmp_addr = { 0 }; - gboolean success = FALSE; - glong tmp_prefix; - - gtk_tree_model_get (model, iter, column, &item, -1); - if (out_raw) - *out_raw = item; - if (!item || !strlen (item)) { - if (!out_raw) - g_free (item); - return fail_if_missing ? FALSE : TRUE; - } - - errno = 0; - - /* Is it a prefix? */ - if (!strchr (item, '.')) { - tmp_prefix = strtol (item, NULL, 10); - if (!errno && tmp_prefix >= 0 && tmp_prefix <= 32) { - *out = tmp_prefix; - success = TRUE; - goto out; - } - } - - /* Is it a netmask? */ - if (inet_pton (AF_INET, item, &tmp_addr) > 0) { - *out = nm_utils_ip4_netmask_to_prefix (tmp_addr.s_addr); - success = TRUE; - } - -out: - if (!out_raw) - g_free (item); - return success; -} - -static gboolean -get_one_addr (GtkTreeModel *model, - GtkTreeIter *iter, - int column, - gboolean fail_if_missing, - char **out, - char **out_raw) -{ - char *item = NULL; - struct in_addr tmp_addr = { 0 }; - - gtk_tree_model_get (model, iter, column, &item, -1); - if (out_raw) - *out_raw = item; - if (!item || !strlen (item)) { - if (!out_raw) - g_free (item); - return fail_if_missing ? FALSE : TRUE; - } - - if (inet_pton (AF_INET, item, &tmp_addr) == 0) - return FALSE; - - if (tmp_addr.s_addr == 0) { - if (!out_raw) - g_free (item); - return fail_if_missing ? FALSE : TRUE; - } - - *out = item; - return TRUE; -} - static void validate (GtkWidget *dialog) { @@ -183,27 +68,28 @@ validate (GtkWidget *dialog) while (iter_valid) { char *addr = NULL, *next_hop = NULL; - guint32 prefix = 0, metric = 0; + guint32 prefix = 0; + gint64 metric = -1; /* Address */ - if (!get_one_addr (model, &tree_iter, COL_ADDRESS, TRUE, &addr, NULL)) + if (!utils_tree_model_get_address (model, &tree_iter, COL_ADDRESS, AF_INET, TRUE, &addr, NULL)) goto done; g_free (addr); /* Prefix */ - if (!get_one_prefix (model, &tree_iter, COL_PREFIX, TRUE, &prefix, NULL)) + if (!utils_tree_model_get_ip4_prefix (model, &tree_iter, COL_PREFIX, TRUE, &prefix, NULL)) goto done; /* Don't allow zero prefix for now - that's not supported in libnm-util */ if (prefix == 0) goto done; /* Next hop (optional) */ - if (!get_one_addr (model, &tree_iter, COL_NEXT_HOP, FALSE, &next_hop, NULL)) + if (!utils_tree_model_get_address (model, &tree_iter, COL_NEXT_HOP, AF_INET, FALSE, &next_hop, NULL)) goto done; g_free (next_hop); /* Metric (optional) */ - if (!get_one_int (model, &tree_iter, COL_METRIC, G_MAXUINT32, FALSE, &metric, NULL)) + if (!utils_tree_model_get_int64 (model, &tree_iter, COL_METRIC, 0, G_MAXUINT32, FALSE, &metric, NULL)) goto done; iter_valid = gtk_tree_model_iter_next (model, &tree_iter); @@ -690,19 +576,20 @@ cell_error_data_func (GtkTreeViewColumn *tree_column, guint32 col = GPOINTER_TO_UINT (data); char *value = NULL; char *addr, *next_hop; - guint32 prefix, metric; + guint32 prefix; + gint64 metric; const char *color = "red"; gboolean invalid = FALSE; if (col == COL_ADDRESS) - invalid = !get_one_addr (tree_model, iter, COL_ADDRESS, TRUE, &addr, &value); + invalid = !utils_tree_model_get_address (tree_model, iter, COL_ADDRESS, AF_INET, TRUE, &addr, &value); else if (col == COL_PREFIX) - invalid = !get_one_prefix (tree_model, iter, COL_PREFIX, TRUE, &prefix, &value) + invalid = !utils_tree_model_get_ip4_prefix (tree_model, iter, COL_PREFIX, TRUE, &prefix, &value) || prefix == 0; else if (col == COL_NEXT_HOP) - invalid = !get_one_addr (tree_model, iter, COL_NEXT_HOP, FALSE, &next_hop, &value); + invalid = !utils_tree_model_get_address (tree_model, iter, COL_NEXT_HOP, AF_INET, FALSE, &next_hop, &value); else if (col == COL_METRIC) - invalid = !get_one_int (tree_model, iter, COL_METRIC, G_MAXUINT32, FALSE, &metric, &value); + invalid = !utils_tree_model_get_int64 (tree_model, iter, COL_METRIC, 0, G_MAXUINT32, FALSE, &metric, &value); else g_warn_if_reached (); @@ -764,6 +651,7 @@ ip4_routes_dialog_new (NMSettingIPConfig *s_ip4, gboolean automatic) NMIPRoute *route = nm_setting_ip_config_get_route (s_ip4, i); struct in_addr tmp_addr; char netmask[INET_ADDRSTRLEN], metric[32]; + gint64 metric_int; if (!route) { g_warning ("%s: empty IP4 route structure!", __func__); @@ -774,9 +662,14 @@ ip4_routes_dialog_new (NMSettingIPConfig *s_ip4, gboolean automatic) if (!inet_ntop (AF_INET, &tmp_addr, netmask, sizeof (netmask))) *netmask = '\0'; - /* FIXME */ - g_snprintf (metric, sizeof (metric), "%u", - (guint32) MIN (0, nm_ip_route_get_metric (route))); + metric_int = nm_ip_route_get_metric (route); + if (metric_int >= 0 && metric_int <= G_MAXUINT32) + g_snprintf (metric, sizeof (metric), "%lu", (unsigned long) metric_int); + else { + if (metric_int != -1) + g_warning ("invalid metric %lld", (long long int) metric_int); + metric[0] = 0; + } gtk_list_store_append (store, &model_iter); gtk_list_store_set (store, &model_iter, @@ -922,31 +815,32 @@ ip4_routes_dialog_update_setting (GtkWidget *dialog, NMSettingIPConfig *s_ip4) while (iter_valid) { char *addr = NULL, *next_hop = NULL; - guint32 prefix = 0, metric = 0; + guint32 prefix = 0; + gint64 metric = -1; NMIPRoute *route; /* Address */ - if (!get_one_addr (model, &tree_iter, COL_ADDRESS, TRUE, &addr, NULL)) { + if (!utils_tree_model_get_address (model, &tree_iter, COL_ADDRESS, AF_INET, TRUE, &addr, NULL)) { g_warning ("%s: IPv4 address missing or invalid!", __func__); goto next; } /* Prefix */ - if (!get_one_prefix (model, &tree_iter, COL_PREFIX, TRUE, &prefix, NULL)) { + if (!utils_tree_model_get_ip4_prefix (model, &tree_iter, COL_PREFIX, TRUE, &prefix, NULL)) { g_warning ("%s: IPv4 prefix/netmask missing or invalid!", __func__); g_free (addr); goto next; } /* Next hop (optional) */ - if (!get_one_addr (model, &tree_iter, COL_NEXT_HOP, FALSE, &next_hop, NULL)) { + if (!utils_tree_model_get_address (model, &tree_iter, COL_NEXT_HOP, AF_INET, FALSE, &next_hop, NULL)) { g_warning ("%s: IPv4 next hop invalid!", __func__); g_free (addr); goto next; } /* Metric (optional) */ - if (!get_one_int (model, &tree_iter, COL_METRIC, G_MAXUINT32, FALSE, &metric, NULL)) { + if (!utils_tree_model_get_int64 (model, &tree_iter, COL_METRIC, 0, G_MAXUINT32, FALSE, &metric, NULL)) { g_warning ("%s: IPv4 metric invalid!", __func__); g_free (addr); g_free (next_hop); diff --git a/src/connection-editor/ip6-routes-dialog.c b/src/connection-editor/ip6-routes-dialog.c index 9f90e4b2..95f81ad5 100644 --- a/src/connection-editor/ip6-routes-dialog.c +++ b/src/connection-editor/ip6-routes-dialog.c @@ -50,17 +50,18 @@ static char *last_path = NULL; /* row in treeview */ static int last_column = -1; /* column in treeview */ static gboolean -get_one_int (GtkTreeModel *model, - GtkTreeIter *iter, - int column, - guint32 max_value, - gboolean fail_if_missing, - guint *out, - char **out_raw) +get_one_int64 (GtkTreeModel *model, + GtkTreeIter *iter, + int column, + gint64 min_value, + gint64 max_value, + gboolean fail_if_missing, + gint64 *out, + char **out_raw) { char *item = NULL; gboolean success = FALSE; - long int tmp_int; + long long int tmp_int; gtk_tree_model_get (model, iter, column, &item, -1); if (out_raw) @@ -72,11 +73,11 @@ get_one_int (GtkTreeModel *model, } errno = 0; - tmp_int = strtol (item, NULL, 10); - if (errno || tmp_int < 0 || tmp_int > max_value) + tmp_int = strtoll (item, NULL, 10); + if (errno || tmp_int < min_value || tmp_int > max_value) goto out; - *out = (guint) tmp_int; + *out = (gint64) tmp_int; success = TRUE; out: @@ -85,39 +86,6 @@ out: return success; } -static gboolean -get_one_addr (GtkTreeModel *model, - GtkTreeIter *iter, - int column, - gboolean fail_if_missing, - char **out, - char **out_raw) -{ - char *item = NULL; - struct in6_addr tmp_addr; - - gtk_tree_model_get (model, iter, column, &item, -1); - if (out_raw) - *out_raw = item; - if (!item || !strlen (item)) { - if (!out_raw) - g_free (item); - return fail_if_missing ? FALSE : TRUE; - } - - if (inet_pton (AF_INET6, item, &tmp_addr) == 0) - return FALSE; - - if (IN6_IS_ADDR_UNSPECIFIED (&tmp_addr)) { - if (!out_raw) - g_free (item); - return fail_if_missing ? FALSE : TRUE; - } - - *out = item; - return TRUE; -} - static void validate (GtkWidget *dialog) { @@ -139,25 +107,24 @@ validate (GtkWidget *dialog) while (iter_valid) { char *dest = NULL, *next_hop = NULL; - guint prefix = 0, metric = 0; + gint64 prefix = 0, metric = -1; /* Address */ - if (!get_one_addr (model, &tree_iter, COL_ADDRESS, TRUE, &dest, NULL)) + if (!utils_tree_model_get_address (model, &tree_iter, COL_ADDRESS, AF_INET6, TRUE, &dest, NULL)) goto done; g_free (dest); /* Prefix */ - if ( !get_one_int (model, &tree_iter, COL_PREFIX, 128, TRUE, &prefix, NULL) - || prefix == 0) + if (!utils_tree_model_get_int64 (model, &tree_iter, COL_PREFIX, 1, 128, TRUE, &prefix, NULL)) goto done; /* Next hop (optional) */ - if (!get_one_addr (model, &tree_iter, COL_NEXT_HOP, FALSE, &next_hop, NULL)) + if (!utils_tree_model_get_address (model, &tree_iter, COL_NEXT_HOP, AF_INET6, FALSE, &next_hop, NULL)) goto done; g_free (next_hop); /* Metric (optional) */ - if (!get_one_int (model, &tree_iter, COL_METRIC, G_MAXUINT32, FALSE, &metric, NULL)) + if (!get_one_int64 (model, &tree_iter, COL_METRIC, 0, G_MAXUINT32, FALSE, &metric, NULL)) goto done; iter_valid = gtk_tree_model_iter_next (model, &tree_iter); @@ -635,19 +602,18 @@ cell_error_data_func (GtkTreeViewColumn *tree_column, guint32 col = GPOINTER_TO_UINT (data); char *value = NULL; char *addr, *next_hop; - guint32 prefix, metric; + gint64 prefix, metric; const char *color = "red"; gboolean invalid = FALSE; if (col == COL_ADDRESS) - invalid = !get_one_addr (tree_model, iter, COL_ADDRESS, TRUE, &addr, &value); + invalid = !utils_tree_model_get_address (tree_model, iter, COL_ADDRESS, AF_INET6, TRUE, &addr, &value); else if (col == COL_PREFIX) - invalid = !get_one_int (tree_model, iter, COL_PREFIX, 128, TRUE, &prefix, &value) - || prefix == 0; + invalid = !utils_tree_model_get_int64 (tree_model, iter, COL_PREFIX, 1, 128, TRUE, &prefix, &value); else if (col == COL_NEXT_HOP) - invalid = !get_one_addr (tree_model, iter, COL_NEXT_HOP, FALSE, &next_hop, &value); + invalid = !utils_tree_model_get_address (tree_model, iter, COL_NEXT_HOP, AF_INET6, FALSE, &next_hop, &value); else if (col == COL_METRIC) - invalid = !get_one_int (tree_model, iter, COL_METRIC, G_MAXUINT32, FALSE, &metric, &value); + invalid = !utils_tree_model_get_int64 (tree_model, iter, COL_METRIC, 0, G_MAXUINT32, FALSE, &metric, &value); else g_warn_if_reached (); @@ -708,6 +674,7 @@ ip6_routes_dialog_new (NMSettingIPConfig *s_ip6, gboolean automatic) for (i = 0; i < nm_setting_ip_config_get_num_routes (s_ip6); i++) { NMIPRoute *route = nm_setting_ip_config_get_route (s_ip6, i); char prefix[32], metric[32]; + gint64 metric_int; if (!route) { g_warning ("%s: empty IP6 route structure!", __func__); @@ -716,9 +683,14 @@ ip6_routes_dialog_new (NMSettingIPConfig *s_ip6, gboolean automatic) g_snprintf (prefix, sizeof (prefix), "%u", nm_ip_route_get_prefix (route)); - /* FIXME */ - g_snprintf (metric, sizeof (metric), "%u", - (guint32) MIN (0, nm_ip_route_get_metric (route))); + metric_int = nm_ip_route_get_metric (route); + if (metric_int >= 0 && metric_int <= G_MAXUINT32) + g_snprintf (metric, sizeof (metric), "%lu", (unsigned long) metric_int); + else { + if (metric_int != -1) + g_warning ("invalid metric %lld", (long long int) metric_int); + metric[0] = 0; + } gtk_list_store_append (store, &model_iter); gtk_list_store_set (store, &model_iter, @@ -864,32 +836,31 @@ ip6_routes_dialog_update_setting (GtkWidget *dialog, NMSettingIPConfig *s_ip6) while (iter_valid) { char *dest = NULL, *next_hop = NULL; - guint prefix = 0, metric = 0; + gint64 prefix = 0, metric = -1; NMIPRoute *route; /* Address */ - if (!get_one_addr (model, &tree_iter, COL_ADDRESS, TRUE, &dest, NULL)) { + if (!utils_tree_model_get_address (model, &tree_iter, COL_ADDRESS, AF_INET6, TRUE, &dest, NULL)) { g_warning ("%s: IPv6 address missing or invalid!", __func__); goto next; } /* Prefix */ - if ( !get_one_int (model, &tree_iter, COL_PREFIX, 128, TRUE, &prefix, NULL) - || prefix == 0) { + if (!utils_tree_model_get_int64 (model, &tree_iter, COL_PREFIX, 1, 128, TRUE, &prefix, NULL)) { g_warning ("%s: IPv6 prefix missing or invalid!", __func__); g_free (dest); goto next; } /* Next hop (optional) */ - if (!get_one_addr (model, &tree_iter, COL_NEXT_HOP, FALSE, &next_hop, NULL)) { + if (!utils_tree_model_get_address (model, &tree_iter, COL_NEXT_HOP, AF_INET6, FALSE, &next_hop, NULL)) { g_warning ("%s: IPv6 next hop invalid!", __func__); g_free (dest); goto next; } /* Metric (optional) */ - if (!get_one_int (model, &tree_iter, COL_METRIC, G_MAXUINT32, FALSE, &metric, NULL)) { + if (!utils_tree_model_get_int64 (model, &tree_iter, COL_METRIC, 0, G_MAXUINT32, FALSE, &metric, NULL)) { g_warning ("%s: IPv6 metric invalid!", __func__); g_free (dest); g_free (next_hop); diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am index aac01556..22d3b0c0 100644 --- a/src/utils/Makefile.am +++ b/src/utils/Makefile.am @@ -1,10 +1,16 @@ SUBDIRS= . tests +shared_files = \ + $(top_srcdir)/shared/nm-utils/nm-shared-utils.c \ + $(top_srcdir)/shared/nm-utils/nm-shared-utils.h \ + $(NULL) + noinst_LTLIBRARIES = \ libutils-libnm-glib.la \ libutils-libnm.la libutils_libnm_glib_la_SOURCES = \ + $(shared_files) \ utils.c \ utils.h @@ -12,20 +18,21 @@ libutils_libnm_glib_la_CPPFLAGS = \ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_LIB_LEGACY \ $(GTK_CFLAGS) \ $(LIBNM_GLIB_CFLAGS) \ - "-I${top_srcdir}/shared/" + -I$(top_srcdir)/shared/ libutils_libnm_glib_la_LIBADD = \ $(GTK_LIBS) \ $(LIBNM_GLIB_LIBS) libutils_libnm_la_SOURCES = \ + $(shared_files) \ utils.c \ utils.h libutils_libnm_la_CPPFLAGS = \ $(GTK_CFLAGS) \ $(LIBNM_CFLAGS) \ - "-I${top_srcdir}/shared/" + -I$(top_srcdir)/shared/ libutils_libnm_la_LIBADD = \ $(GTK_LIBS) \ diff --git a/src/utils/utils.c b/src/utils/utils.c index 23e41c36..c3b806e2 100644 --- a/src/utils/utils.c +++ b/src/utils/utils.c @@ -25,8 +25,13 @@ #include "utils.h" #include <string.h> +#include <errno.h> +#include <arpa/inet.h> #include <netinet/ether.h> +#include "nm-utils.h" +#include "nm-utils/nm-shared-utils.h" + /* * utils_ether_addr_valid * @@ -385,3 +390,132 @@ widget_unset_error (GtkWidget *widget) gtk_style_context_remove_class (gtk_widget_get_style_context (widget), "error"); } + +gboolean +utils_tree_model_get_int64 (GtkTreeModel *model, + GtkTreeIter *iter, + int column, + gint64 min_value, + gint64 max_value, + gboolean fail_if_missing, + gint64 *out, + char **out_raw) +{ + char *item = NULL; + gboolean success = FALSE; + gint64 val; + + g_return_val_if_fail (model, FALSE); + g_return_val_if_fail (iter, FALSE); + + gtk_tree_model_get (model, iter, column, &item, -1); + if (out_raw) + *out_raw = item; + if (!item || !strlen (item)) { + if (!out_raw) + g_free (item); + return fail_if_missing ? FALSE : TRUE; + } + + val = _nm_utils_ascii_str_to_int64 (item, 10, min_value, max_value, 0); + if (errno) + goto out; + + *out = val; + success = TRUE; +out: + if (!out_raw) + g_free (item); + return success; +} + +gboolean +utils_tree_model_get_address (GtkTreeModel *model, + GtkTreeIter *iter, + int column, + int family, + gboolean fail_if_missing, + char **out, + char **out_raw) +{ + char *item = NULL; + union { + struct in_addr addr4; + struct in6_addr addr6; + } tmp_addr; + + g_return_val_if_fail (model, FALSE); + g_return_val_if_fail (iter, FALSE); + g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); + + gtk_tree_model_get (model, iter, column, &item, -1); + if (out_raw) + *out_raw = item; + if (!item || !strlen (item)) { + if (!out_raw) + g_free (item); + return fail_if_missing ? FALSE : TRUE; + } + + if (inet_pton (family, item, &tmp_addr) == 0) + return FALSE; + + if ( (family == AF_INET && tmp_addr.addr4.s_addr == 0) + || (family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED (&tmp_addr.addr6))) { + if (!out_raw) + g_free (item); + return fail_if_missing ? FALSE : TRUE; + } + + *out = item; + return TRUE; +} + +gboolean +utils_tree_model_get_ip4_prefix (GtkTreeModel *model, + GtkTreeIter *iter, + int column, + gboolean fail_if_missing, + guint32 *out, + char **out_raw) +{ + char *item = NULL; + struct in_addr tmp_addr = { 0 }; + gboolean success = FALSE; + glong tmp_prefix; + + g_return_val_if_fail (model, FALSE); + g_return_val_if_fail (iter, FALSE); + + gtk_tree_model_get (model, iter, column, &item, -1); + if (out_raw) + *out_raw = item; + if (!item || !strlen (item)) { + if (!out_raw) + g_free (item); + return fail_if_missing ? FALSE : TRUE; + } + + errno = 0; + + /* Is it a prefix? */ + if (!strchr (item, '.')) { + tmp_prefix = strtol (item, NULL, 10); + if (!errno && tmp_prefix >= 0 && tmp_prefix <= 32) { + *out = tmp_prefix; + success = TRUE; + goto out; + } + } + + /* Is it a netmask? */ + if (inet_pton (AF_INET, item, &tmp_addr) > 0) { + *out = nm_utils_ip4_netmask_to_prefix (tmp_addr.s_addr); + success = TRUE; + } + +out: + if (!out_raw) + g_free (item); + return success; +} diff --git a/src/utils/utils.h b/src/utils/utils.h index ab903662..544833a4 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -84,5 +84,29 @@ void utils_fake_return_key (GdkEventKey *event); void widget_set_error (GtkWidget *widget); void widget_unset_error (GtkWidget *widget); +gboolean utils_tree_model_get_int64 (GtkTreeModel *model, + GtkTreeIter *iter, + int column, + gint64 min_value, + gint64 max_value, + gboolean fail_if_missing, + gint64 *out, + char **out_raw); + +gboolean utils_tree_model_get_address (GtkTreeModel *model, + GtkTreeIter *iter, + int column, + int family, + gboolean fail_if_missing, + char **out, + char **out_raw); + +gboolean utils_tree_model_get_ip4_prefix (GtkTreeModel *model, + GtkTreeIter *iter, + int column, + gboolean fail_if_missing, + guint32 *out, + char **out_raw); + #endif /* UTILS_H */ |