summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-02-26 09:51:09 +0100
committerThomas Haller <thaller@redhat.com>2014-02-26 19:15:42 +0100
commit4f3b1eb61659e318a9329b0266a784d9028699e6 (patch)
treed4cddfa61482a7956ee74c629e86425c1f6ebeb9
parent16e8358bec310008eb68b850dc499d3dded6d5aa (diff)
downloadNetworkManager-4f3b1eb61659e318a9329b0266a784d9028699e6.tar.gz
core: add nm_utils_log_connection_diff
Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r--src/NetworkManagerUtils.c239
-rw-r--r--src/NetworkManagerUtils.h2
-rw-r--r--src/tests/Makefile.am1
-rw-r--r--src/tests/test-general.c49
4 files changed, 291 insertions, 0 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 9db609a1dc..23a0bcda42 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -39,6 +39,8 @@
#include "nm-manager-auth.h"
#include "nm-posix-signals.h"
+#include "nm-util-private.h"
+
/*
* nm_ethernet_address_is_valid
*
@@ -908,4 +910,241 @@ nm_utils_get_monotonic_timestamp_s (void)
return (((gint64) tp.tv_sec) + monotonic_timestamp_offset_sec);
}
+struct _log_connection_setting_data
+{
+ const char *name;
+ NMSetting *setting;
+ NMSetting *diff_base_setting;
+ GHashTable *setting_diff;
+};
+
+struct _log_connection_setting_item
+{
+ const char *item_name;
+ NMSettingDiffResult diff_result;
+};
+
+static gint
+_log_connection_sort_hashes_fcn (gconstpointer a, gconstpointer b)
+{
+ const struct _log_connection_setting_data *v1 = a;
+ const struct _log_connection_setting_data *v2 = b;
+ guint32 p1, p2;
+ const NMUtilPrivateData *data;
+ NMSetting *s1, *s2;
+
+ s1 = v1->setting ? v1->setting : v1->diff_base_setting;
+ s2 = v2->setting ? v2->setting : v2->diff_base_setting;
+
+ g_assert (s1 && s2);
+
+ data = nm_util_get_private_data ();
+ p1 = (*data->fcn_nm_setting_get_setting_priority) (s1);
+ p2 = (*data->fcn_nm_setting_get_setting_priority) (s2);
+
+ if (p1 != p2)
+ return p1 > p2 ? 1 : -1;
+
+ return strcmp (v1->name, v2->name);
+}
+
+static GArray *
+_log_connection_sort_hashes (NMConnection *connection, NMConnection *diff_base, GHashTable *connection_diff)
+{
+ GHashTableIter iter;
+ GArray *sorted_hashes;
+ struct _log_connection_setting_data setting_data;
+
+ sorted_hashes = g_array_sized_new (TRUE, FALSE, sizeof (struct _log_connection_setting_data), g_hash_table_size (connection_diff));
+
+ g_hash_table_iter_init (&iter, connection_diff);
+ while (g_hash_table_iter_next (&iter, (gpointer) &setting_data.name, (gpointer) &setting_data.setting_diff)) {
+ setting_data.setting = nm_connection_get_setting_by_name (connection, setting_data.name);
+ setting_data.diff_base_setting = diff_base ? nm_connection_get_setting_by_name (diff_base, setting_data.name) : NULL;
+ g_assert (setting_data.setting || setting_data.diff_base_setting);
+ g_array_append_val (sorted_hashes, setting_data);
+ }
+
+ g_array_sort (sorted_hashes, _log_connection_sort_hashes_fcn);
+ return sorted_hashes;
+}
+
+static gint
+_log_connection_sort_names_fcn (gconstpointer a, gconstpointer b)
+{
+ const struct _log_connection_setting_item *v1 = a;
+ const struct _log_connection_setting_item *v2 = b;
+
+ /* we want to first show the items, that disappeared, then the one that changed and
+ * then the ones that were added. */
+
+ if ((v1->diff_result & NM_SETTING_DIFF_RESULT_IN_A) != (v1->diff_result & NM_SETTING_DIFF_RESULT_IN_A))
+ return (v1->diff_result & NM_SETTING_DIFF_RESULT_IN_A) ? -1 : 1;
+ if ((v1->diff_result & NM_SETTING_DIFF_RESULT_IN_B) != (v1->diff_result & NM_SETTING_DIFF_RESULT_IN_B))
+ return (v1->diff_result & NM_SETTING_DIFF_RESULT_IN_B) ? 1 : -1;
+ return strcmp (v1->item_name, v2->item_name);
+}
+
+static char *
+_log_connection_get_property (NMSetting *setting, const char *name)
+{
+ GValue val = G_VALUE_INIT;
+ char *s;
+
+ g_return_val_if_fail (setting, NULL);
+
+ if (nm_setting_get_secret_flags (setting, name, NULL, NULL))
+ return g_strdup ("****");
+
+ if (!(*nm_util_get_private_data()->fcn_nm_setting_get_property) (setting, name, &val))
+ g_return_val_if_reached (FALSE);
+
+ if (G_VALUE_HOLDS_STRING (&val)) {
+ const char *val_s;
+
+ /* for NULL, we don't want to return the string "NULL". */
+ val_s = g_value_get_string (&val);
+ if (!val_s)
+ s = g_strdup ("NULL");
+ else {
+ char *escaped = g_strescape (val_s, "'");
+
+ s = g_strdup_printf ("'%s'", escaped);
+ g_free (escaped);
+ }
+ } else {
+ s = g_strdup_value_contents (&val);
+ if (s == NULL)
+ s = g_strdup ("NULL");
+ else {
+ char *escaped = g_strescape (s, "'");
+
+ g_free (s);
+ s = escaped;
+ }
+ }
+ g_value_unset(&val);
+ return s;
+}
+
+static void
+_log_connection_sort_names (struct _log_connection_setting_data *setting_data, GArray *sorted_names)
+{
+ GHashTableIter iter;
+ struct _log_connection_setting_item item;
+ gpointer p;
+
+ g_array_set_size (sorted_names, 0);
+
+ g_hash_table_iter_init (&iter, setting_data->setting_diff);
+ while (g_hash_table_iter_next (&iter, (gpointer) &item.item_name, &p)) {
+ item.diff_result = GPOINTER_TO_UINT (p);
+ g_array_append_val (sorted_names, item);
+ }
+
+ g_array_sort (sorted_names, _log_connection_sort_names_fcn);
+}
+
+void
+nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, guint32 level, guint64 domain, const char *name, const char *prefix)
+{
+ GHashTable *connection_diff = NULL;
+ GArray *sorted_hashes;
+ GArray *sorted_names = NULL;
+ int i, j;
+ gboolean connection_diff_are_same;
+ gboolean print_header = TRUE;
+ gboolean print_setting_header;
+ GString *str1;
+
+ g_return_if_fail (NM_IS_CONNECTION (connection));
+ g_return_if_fail (!diff_base || (NM_IS_CONNECTION (diff_base) && diff_base != connection));
+
+ if (!nm_logging_enabled (level, domain))
+ return;
+
+ if (!prefix)
+ prefix = "";
+ if (!name)
+ name = "";
+
+ connection_diff_are_same = nm_connection_diff (connection, diff_base, NM_SETTING_COMPARE_FLAG_EXACT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT, &connection_diff);
+ if (connection_diff_are_same) {
+ if (diff_base)
+ nm_log (domain, level, "%sconnection '%s' (%p and %p): no difference", prefix, name, connection, diff_base);
+ else
+ nm_log (domain, level, "%sconnection '%s' (%p): no properties set", prefix, name, connection);
+ g_assert (!connection_diff);
+ return;
+ }
+
+ sorted_hashes = _log_connection_sort_hashes (connection, diff_base, connection_diff);
+ if (sorted_hashes->len <= 0)
+ goto out;
+
+ sorted_names = g_array_new (FALSE, FALSE, sizeof (struct _log_connection_setting_item));
+ str1 = g_string_new (NULL);
+
+ for (i = 0; i < sorted_hashes->len; i++) {
+ struct _log_connection_setting_data *setting_data = &g_array_index (sorted_hashes, struct _log_connection_setting_data, i);
+
+ _log_connection_sort_names (setting_data, sorted_names);
+ print_setting_header = TRUE;
+ for (j = 0; j < sorted_names->len; j++) {
+ char *str_conn, *str_diff;
+ struct _log_connection_setting_item *item = &g_array_index (sorted_names, struct _log_connection_setting_item, j);
+
+ str_conn = (item->diff_result & NM_SETTING_DIFF_RESULT_IN_A)
+ ? _log_connection_get_property (setting_data->setting, item->item_name)
+ : NULL;
+ str_diff = (item->diff_result & NM_SETTING_DIFF_RESULT_IN_B)
+ ? _log_connection_get_property (setting_data->diff_base_setting, item->item_name)
+ : NULL;
+
+ if (print_header) {
+ if (diff_base)
+ nm_log (domain, level, "%sconnection '%s' (%p < %p):", prefix, name, connection, diff_base);
+ else
+ nm_log (domain, level, "%sconnection '%s' (%p):", prefix, name, connection);
+ print_header = FALSE;
+ }
+#define _NM_LOG_ALIGN "-25"
+ if (print_setting_header) {
+ if (diff_base) {
+ if (setting_data->setting && setting_data->diff_base_setting)
+ g_string_printf (str1, "%p < %p", setting_data->setting, setting_data->diff_base_setting);
+ else if (setting_data->diff_base_setting)
+ g_string_printf (str1, "*missing* < %p", setting_data->diff_base_setting);
+ else
+ g_string_printf (str1, "%p < *missing*", setting_data->setting);
+ nm_log (domain, level, "%s%"_NM_LOG_ALIGN"s [ %s ]", prefix, setting_data->name, str1->str);
+ } else
+ nm_log (domain, level, "%s%"_NM_LOG_ALIGN"s [ %p ]", prefix, setting_data->name, setting_data->setting);
+ print_setting_header = FALSE;
+ }
+ g_string_printf (str1, "%s.%s", setting_data->name, item->item_name);
+ switch (item->diff_result & (NM_SETTING_DIFF_RESULT_IN_A | NM_SETTING_DIFF_RESULT_IN_B)) {
+ case NM_SETTING_DIFF_RESULT_IN_B:
+ nm_log (domain, level, "%s%"_NM_LOG_ALIGN"s < %s", prefix, str1->str, str_diff ? str_diff : "NULL");
+ break;
+ case NM_SETTING_DIFF_RESULT_IN_A:
+ nm_log (domain, level, "%s%"_NM_LOG_ALIGN"s = %s", prefix, str1->str, str_conn ? str_conn : "NULL");
+ break;
+ default:
+ nm_log (domain, level, "%s%"_NM_LOG_ALIGN"s = %s < %s", prefix, str1->str, str_conn ? str_conn : "NULL", str_diff ? str_diff : "NULL");
+ break;
+#undef _NM_LOG_ALIGN
+ }
+ g_free (str_conn);
+ g_free (str_diff);
+ }
+ }
+
+ g_array_free (sorted_names, TRUE);
+ g_string_free (str1, TRUE);
+out:
+ g_hash_table_destroy (connection_diff);
+ g_array_free (sorted_hashes, TRUE);
+}
+
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index ee234dda80..009f9ee757 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -104,4 +104,6 @@ gint64 nm_utils_get_monotonic_timestamp_us (void);
gint64 nm_utils_get_monotonic_timestamp_ms (void);
gint32 nm_utils_get_monotonic_timestamp_s (void);
+void nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, guint32 level, guint64 domain, const char *name, const char *prefix);
+
#endif /* NETWORK_MANAGER_UTILS_H */
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index 4dda163c48..b84be54fe0 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -3,6 +3,7 @@ AM_CPPFLAGS = \
-I$(top_builddir)/include \
-I$(top_srcdir)/libnm-util \
-I$(top_builddir)/libnm-util \
+ -I$(top_srcdir)/src/logging \
-I$(top_srcdir)/src/platform \
-I$(top_srcdir)/src/dhcp-manager \
-I$(top_srcdir)/src \
diff --git a/src/tests/test-general.c b/src/tests/test-general.c
index 3fd7115cb0..de920232a2 100644
--- a/src/tests/test-general.c
+++ b/src/tests/test-general.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include "NetworkManagerUtils.h"
+#include "nm-logging.h"
static void
@@ -130,6 +131,50 @@ test_nm_utils_ip6_address_clear_host_address (void)
g_rand_free (rand);
}
+
+static void
+test_nm_utils_log_connection_diff()
+{
+ NMConnection *connection;
+ NMConnection *connection2;
+
+ nm_log (LOGD_CORE, LOGL_DEBUG, "START TEST test_nm_utils_log_connection_diff...");
+
+ connection = nm_connection_new ();
+ nm_connection_add_setting (connection, nm_setting_connection_new ());
+ nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test1", ">>> ");
+
+ nm_connection_add_setting (connection, nm_setting_wired_new ());
+ nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test2", ">>> ");
+
+ connection2 = nm_connection_duplicate (connection);
+ nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test3", ">>> ");
+
+ g_object_set (nm_connection_get_setting_connection (connection),
+ NM_SETTING_CONNECTION_ID, "id",
+ NM_SETTING_CONNECTION_UUID, "uuid",
+ NULL);
+ g_object_set (nm_connection_get_setting_connection (connection2),
+ NM_SETTING_CONNECTION_ID, "id2",
+ NM_SETTING_CONNECTION_MASTER, "master2",
+ NULL);
+ nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test4", ">>> ");
+
+ nm_connection_add_setting (connection, nm_setting_802_1x_new ());
+ nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test5", ">>> ");
+
+ g_object_set (nm_connection_get_setting_802_1x (connection),
+ NM_SETTING_802_1X_PASSWORD, "id2",
+ NM_SETTING_802_1X_PASSWORD_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED,
+ NULL);
+ nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test6", ">>> ");
+ nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test7", ">>> ");
+ nm_utils_log_connection_diff (connection2, connection, LOGL_DEBUG, LOGD_CORE, "test8", ">>> ");
+
+ g_object_unref (connection);
+ g_object_unref (connection2);
+}
+
/*******************************************/
int
@@ -139,8 +184,12 @@ main (int argc, char **argv)
g_type_init ();
+ nm_logging_syslog_openlog (TRUE);
+ nm_logging_setup ("DEBUG", "ALL", NULL, NULL);
+
g_test_add_func ("/general/nm_utils_ascii_str_to_int64", test_nm_utils_ascii_str_to_int64);
g_test_add_func ("/general/nm_utils_ip6_address_clear_host_address", test_nm_utils_ip6_address_clear_host_address);
+ g_test_add_func ("/general/nm_utils_log_connection_diff", test_nm_utils_log_connection_diff);
return g_test_run ();
}