summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2016-10-14 11:46:47 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2016-10-14 11:46:47 +0200
commitb54b47ac70e1d6eb451a902c36db930a6351a5bb (patch)
tree6833ae7c8c98e360f4f914ac34bdb44ff85bb864
parenta5f3e6e82f0f3d80ed8a1e191c9ffc219222243f (diff)
parentce6801d965b7c13c745f4ed0136457e30b84a4e0 (diff)
downloadnetwork-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.ac2
-rw-r--r--shared/Makefile.am2
-rw-r--r--shared/nm-utils/nm-shared-utils.c239
-rw-r--r--shared/nm-utils/nm-shared-utils.h66
-rw-r--r--src/connection-editor/ip4-routes-dialog.c160
-rw-r--r--src/connection-editor/ip6-routes-dialog.c101
-rw-r--r--src/utils/Makefile.am11
-rw-r--r--src/utils/utils.c134
-rw-r--r--src/utils/utils.h24
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 */