summary refs log tree commit diff
path: root/libnm-core/nm-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-core/nm-utils.c')
-rw-r--r--libnm-core/nm-utils.c188
1 files changed, 130 insertions, 58 deletions
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index a535b679..ebbbfd3a 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -35,11 +35,13 @@
 #include <net/if.h>
 #include <linux/pkt_sched.h>
 
-#if WITH_JSON_VALIDATION
+#if WITH_JANSSON
 #include "nm-json.h"
+#include <jansson.h>
 #endif
 
 #include "nm-utils/nm-enum-utils.h"
+#include "nm-utils/nm-hash-utils.h"
 #include "nm-common-macros.h"
 #include "nm-utils-private.h"
 #include "nm-setting-private.h"
@@ -148,7 +150,7 @@ init_lang_to_encodings_hash (void)
 	if (G_UNLIKELY (langToEncodings5 == NULL)) {
 		/* Five-letter codes */
 		enc = (struct IsoLangToEncodings *) &isoLangEntries5[0];
-		langToEncodings5 = g_hash_table_new (nm_str_hash, g_str_equal);
+		langToEncodings5 = g_hash_table_new (g_str_hash, g_str_equal);
 		while (enc->lang) {
 			g_hash_table_insert (langToEncodings5, (gpointer) enc->lang,
 			                     (gpointer) enc->encodings);
@@ -159,7 +161,7 @@ init_lang_to_encodings_hash (void)
 	if (G_UNLIKELY (langToEncodings2 == NULL)) {
 		/* Two-letter codes */
 		enc = (struct IsoLangToEncodings *) &isoLangEntries2[0];
-		langToEncodings2 = g_hash_table_new (nm_str_hash, g_str_equal);
+		langToEncodings2 = g_hash_table_new (g_str_hash, g_str_equal);
 		while (enc->lang) {
 			g_hash_table_insert (langToEncodings2, (gpointer) enc->lang,
 			                     (gpointer) enc->encodings);
@@ -253,6 +255,8 @@ _nm_utils_init (void)
 	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 
+	nm_g_type_init ();
+
 	_nm_dbus_errors_init ();
 }
 
@@ -464,7 +468,7 @@ _nm_utils_string_slist_validate (GSList *list, const char **valid_values)
  * @hash: a #GHashTable
  *
  * Utility function to iterate over a hash table and return
- * its values as a #GSList.
+ * it's values as a #GSList.
  *
  * Returns: (element-type gpointer) (transfer container): a newly allocated #GSList
  * containing the values of the hash table. The caller must free the
@@ -542,7 +546,7 @@ _nm_utils_strdict_from_dbus (GVariant *dbus_value,
 	const char *key, *value;
 	GHashTable *hash;
 
-	hash = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free);
+	hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 	g_variant_iter_init (&iter, dbus_value);
 	while (g_variant_iter_next (&iter, "{&s&s}", &key, &value))
 		g_hash_table_insert (hash, g_strdup (key), g_strdup (value));
@@ -557,7 +561,7 @@ _nm_utils_copy_strdict (GHashTable *strdict)
 	GHashTableIter iter;
 	gpointer key, value;
 
-	copy = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free);
+	copy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 	if (strdict) {
 		g_hash_table_iter_init (&iter, strdict);
 		while (g_hash_table_iter_next (&iter, &key, &value))
@@ -1879,7 +1883,7 @@ GVariant *
 nm_utils_ip_addresses_to_variant (GPtrArray *addresses)
 {
 	GVariantBuilder builder;
-	guint i;
+	int i;
 
 	g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
 
@@ -1887,8 +1891,8 @@ nm_utils_ip_addresses_to_variant (GPtrArray *addresses)
 		for (i = 0; i < addresses->len; i++) {
 			NMIPAddress *addr = addresses->pdata[i];
 			GVariantBuilder addr_builder;
-			gs_free const char **names = NULL;
-			guint j, len;
+			char **names;
+			int n;
 
 			g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}"));
 			g_variant_builder_add (&addr_builder, "{sv}",
@@ -1898,12 +1902,13 @@ nm_utils_ip_addresses_to_variant (GPtrArray *addresses)
 			                       "prefix",
 			                       g_variant_new_uint32 (nm_ip_address_get_prefix (addr)));
 
-			names = _nm_ip_address_get_attribute_names (addr, TRUE, &len);
-			for (j = 0; j < len; j++) {
+			names = nm_ip_address_get_attribute_names (addr);
+			for (n = 0; names[n]; n++) {
 				g_variant_builder_add (&addr_builder, "{sv}",
-				                       names[j],
-				                       nm_ip_address_get_attribute (addr, names[j]));
+				                       names[n],
+				                       nm_ip_address_get_attribute (addr, names[n]));
 			}
+			g_strfreev (names);
 
 			g_variant_builder_add (&builder, "a{sv}", &addr_builder);
 		}
@@ -2221,7 +2226,7 @@ _nm_utils_string_append_tc_qdisc_rest (GString *string, NMTCQdisc *qdisc)
  *
  * Returns: formatted string or %NULL
  *
- * Since: 1.12
+ * Since: 1.10.2
  */
 char *
 nm_utils_tc_qdisc_to_str (NMTCQdisc *qdisc, GError **error)
@@ -2322,7 +2327,7 @@ _tc_read_common_opts (const char *str,
  *
  * Returns: the %NMTCQdisc or %NULL
  *
- * Since: 1.12
+ * Since: 1.10.2
  */
 NMTCQdisc *
 nm_utils_tc_qdisc_from_str (const char *str, GError **error)
@@ -2411,7 +2416,7 @@ _string_append_tc_action (GString *string, NMTCAction *action, GError **error)
  *
  * Returns: formatted string or %NULL
  *
- * Since: 1.12
+ * Since: 1.10.2
  */
 char *
 nm_utils_tc_action_to_str (NMTCAction *action, GError **error)
@@ -2437,7 +2442,7 @@ nm_utils_tc_action_to_str (NMTCAction *action, GError **error)
  *
  * Returns: the %NMTCAction or %NULL
  *
- * Since: 1.12
+ * Since: 1.10.2
  */
 NMTCAction *
 nm_utils_tc_action_from_str (const char *str, GError **error)
@@ -2453,10 +2458,10 @@ nm_utils_tc_action_from_str (const char *str, GError **error)
 	nm_assert (str);
 	nm_assert (!error || !*error);
 
-	ht = nm_utils_parse_variant_attributes (str,
-	                                        ' ', ' ', FALSE,
-	                                        tc_action_attribute_spec,
-	                                        error);
+        ht = nm_utils_parse_variant_attributes (str,
+                                                ' ', ' ', FALSE,
+                                                tc_action_attribute_spec,
+                                                error);
 	if (!ht)
 		return FALSE;
 
@@ -2492,10 +2497,10 @@ nm_utils_tc_action_from_str (const char *str, GError **error)
 			return NULL;
 		}
 
-		options = nm_utils_parse_variant_attributes (rest,
-		                                             ' ', ' ', FALSE,
-		                                             attrs,
-		                                             error);
+	        options = nm_utils_parse_variant_attributes (rest,
+	                                                     ' ', ' ', FALSE,
+	                                                     attrs,
+	                                                     error);
 		if (!options) {
 			nm_tc_action_unref (action);
 			return NULL;
@@ -2555,7 +2560,7 @@ _nm_utils_string_append_tc_tfilter_rest (GString *string, NMTCTfilter *tfilter,
  *
  * Returns: formatted string or %NULL
  *
- * Since: 1.12
+ * Since: 1.10.2
  */
 char *
 nm_utils_tc_tfilter_to_str (NMTCTfilter *tfilter, GError **error)
@@ -2590,7 +2595,7 @@ static const NMVariantAttributeSpec * const tc_tfilter_attribute_spec[] = {
  *
  * Returns: the %NMTCTfilter or %NULL
  *
- * Since: 1.12
+ * Since: 1.10.2
  */
 NMTCTfilter *
 nm_utils_tc_tfilter_from_str (const char *str, GError **error)
@@ -3439,28 +3444,59 @@ nm_utils_wifi_5ghz_freqs (void)
  * @strength: the access point strength, from 0 to 100
  *
  * Converts @strength into a 4-character-wide graphical representation of
- * strength suitable for printing to stdout.
- *
- * Previous versions used to take a guess at the terminal type and possibly
- * return a wide UTF-8 encoded string. Now it always returns a 7-bit
- * clean strings of one to 0 to 4 asterisks. Users that actually need
- * the functionality are encouraged to make their implementations instead.
+ * strength suitable for printing to stdout. If the current locale and terminal
+ * support it, this will use unicode graphics characters to represent
+ * "bars". Otherwise it will use 0 to 4 asterisks.
  *
  * Returns: the graphical representation of the access point strength
  */
 const char *
 nm_utils_wifi_strength_bars (guint8 strength)
 {
+	static const char *strength_full, *strength_high, *strength_med, *strength_low, *strength_none;
+
+	if (G_UNLIKELY (strength_full == NULL)) {
+		gboolean can_show_graphics = TRUE;
+		char *locale_str;
+
+		if (!g_get_charset (NULL)) {
+			/* Non-UTF-8 locale */
+			locale_str = g_locale_from_utf8 ("\342\226\202\342\226\204\342\226\206\342\226\210", -1, NULL, NULL, NULL);
+			if (locale_str)
+				g_free (locale_str);
+			else
+				can_show_graphics = FALSE;
+		}
+
+		/* The linux console font doesn't have these characters */
+		if (g_strcmp0 (g_getenv ("TERM"), "linux") == 0)
+			can_show_graphics = FALSE;
+
+		if (can_show_graphics) {
+			strength_full = /* ▂▄▆█ */ "\342\226\202\342\226\204\342\226\206\342\226\210";
+			strength_high = /* ▂▄▆_ */ "\342\226\202\342\226\204\342\226\206_";
+			strength_med  = /* ▂▄__ */ "\342\226\202\342\226\204__";
+			strength_low  = /* ▂___ */ "\342\226\202___";
+			strength_none = /* ____ */ "____";
+		} else {
+			strength_full = "****";
+			strength_high = "*** ";
+			strength_med  = "**  ";
+			strength_low  = "*   ";
+			strength_none = "    ";
+		}
+	}
+
 	if (strength > 80)
-		return "****";
+		return strength_full;
 	else if (strength > 55)
-		return "*** ";
+		return strength_high;
 	else if (strength > 30)
-		return "**  ";
+		return strength_med;
 	else if (strength > 5)
-		return "*   ";
+		return strength_low;
 	else
-		return "    ";
+		return strength_none;
 }
 
 /**
@@ -3662,7 +3698,7 @@ _nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize buffer_length, gs
 /**
  * nm_utils_hwaddr_aton:
  * @asc: the ASCII representation of a hardware address
- * @buffer: (type guint8) (array length=length): buffer to store the result into
+ * @buffer: buffer to store the result into
  * @length: the expected length in bytes of the result and
  * the size of the buffer in bytes.
  *
@@ -3894,9 +3930,9 @@ _nm_utils_hwaddr_canonical_or_invalid (const char *mac, gssize length)
 
 /**
  * nm_utils_hwaddr_matches:
- * @hwaddr1: (nullable): pointer to a binary or ASCII hardware address, or %NULL
+ * @hwaddr1: pointer to a binary or ASCII hardware address, or %NULL
  * @hwaddr1_len: size of @hwaddr1, or -1 if @hwaddr1 is ASCII
- * @hwaddr2: (nullable): pointer to a binary or ASCII hardware address, or %NULL
+ * @hwaddr2: pointer to a binary or ASCII hardware address, or %NULL
  * @hwaddr2_len: size of @hwaddr2, or -1 if @hwaddr2 is ASCII
  *
  * Generalized hardware address comparison function. Tests if @hwaddr1 and
@@ -4335,7 +4371,7 @@ nm_utils_inet_ntop (int addr_family, gconstpointer addr, char *dst)
  *  characters. If set to %NULL, it will return a pointer to an internal, static
  *  buffer (shared with nm_utils_inet6_ntop()).  Beware, that the internal
  *  buffer will be overwritten with ever new call of nm_utils_inet4_ntop() or
- *  nm_utils_inet6_ntop() that does not provide its own @dst buffer. Also,
+ *  nm_utils_inet6_ntop() that does not provied it's own @dst buffer. Also,
  *  using the internal buffer is not thread safe. When in doubt, pass your own
  *  @dst buffer to avoid these issues.
  *
@@ -4359,7 +4395,7 @@ nm_utils_inet4_ntop (in_addr_t inaddr, char *dst)
  *  characters. If set to %NULL, it will return a pointer to an internal, static
  *  buffer (shared with nm_utils_inet4_ntop()).  Beware, that the internal
  *  buffer will be overwritten with ever new call of nm_utils_inet4_ntop() or
- *  nm_utils_inet6_ntop() that does not provide its own @dst buffer. Also,
+ *  nm_utils_inet6_ntop() that does not provied it's own @dst buffer. Also,
  *  using the internal buffer is not thread safe. When in doubt, pass your own
  *  @dst buffer to avoid these issues.
  *
@@ -4586,6 +4622,9 @@ _nm_utils_strstrdictkey_hash (gconstpointer a)
 
 		nm_hash_update_val (&h, k->type);
 		if (k->type & STRSTRDICTKEY_ALL_SET) {
+			gsize n;
+
+			n = 0;
 			p = strchr (k->data, '\0');
 			if (k->type == STRSTRDICTKEY_ALL_SET) {
 				/* the key contains two strings. Continue... */
@@ -4805,7 +4844,7 @@ gssize _nm_utils_dns_option_find_idx (GPtrArray *array, const char *option)
 char *
 nm_utils_enum_to_str (GType type, int value)
 {
-	return _nm_utils_enum_to_str_full (type, value, ", ", NULL);
+	return _nm_utils_enum_to_str_full (type, value, ", ");
 }
 
 /**
@@ -4888,7 +4927,33 @@ _nm_utils_is_json_object_no_validation (const char *str, GError **error)
 	return FALSE;
 }
 
-#if WITH_JSON_VALIDATION
+#if WITH_JANSSON
+
+/* Added in Jansson v2.3 (released Jan 27 2012) */
+#ifndef json_object_foreach
+#define json_object_foreach(object, key, value) \
+    for(key = json_object_iter_key(json_object_iter(object)); \
+        key && (value = json_object_iter_value(json_object_iter_at (object, key) )); \
+        key = json_object_iter_key(json_object_iter_next(object, json_object_iter_at (object, key))))
+#endif
+
+/* Added in Jansson v2.4 (released Sep 23 2012), but travis.ci has v2.2. */
+#ifndef json_boolean
+#define json_boolean(val) ((val) ? json_true() : json_false())
+#endif
+
+/* Added in Jansson v2.5 (released Sep 19 2013), but travis.ci has v2.2. */
+#ifndef json_array_foreach
+#define json_array_foreach(array, index, value) \
+        for (index = 0; \
+             index < json_array_size(array) && (value = json_array_get(array, index)); \
+             index++)
+#endif
+
+/* Added in Jansson v2.7 */
+#ifndef json_boolean_value
+#define json_boolean_value json_is_true
+#endif
 
 static void
 _json_add_object (json_t *json,
@@ -5362,6 +5427,15 @@ nm_utils_is_json_object (const char *str, GError **error)
 	return TRUE;
 }
 
+/* json_object_foreach_safe() is only available since Jansson 2.8,
+ * reimplement it */
+#define _json_object_foreach_safe(object, n, key, value) \
+    for (key = json_object_iter_key (json_object_iter (object)), \
+         n = json_object_iter_next (object, json_object_iter_at (object, key)); \
+         key && (value = json_object_iter_value (json_object_iter_at (object, key))); \
+         key = json_object_iter_key (n), \
+         n = json_object_iter_next (object, json_object_iter_at (object, key)))
+
 gboolean
 _nm_utils_team_config_equal (const char *conf1,
                              const char *conf2,
@@ -5401,7 +5475,7 @@ _nm_utils_team_config_equal (const char *conf1,
 	/* Only consider a given subset of nodes, others can change depending on
 	 * current state */
 	for (i = 0, json = json1; i < 2; i++, json = json2) {
-		json_object_foreach_safe (json, tmp, key, value) {
+		_json_object_foreach_safe (json, tmp, key, value) {
 			if (!NM_IN_STRSET (key, "runner", "link_watch"))
 				json_object_del (json, key);
 		}
@@ -5660,7 +5734,7 @@ done:
 	return updated;
 }
 
-#else /* !WITH_JSON_VALIDATION */
+#else /* WITH_JANSSON */
 
 gboolean
 nm_utils_is_json_object (const char *str, GError **error)
@@ -5952,8 +6026,7 @@ attribute_unescape (const char *start, const char *end)
  *
  * Parse attributes from a string.
  *
- * Returns: (transfer full) (element-type utf8 GVariant): a #GHashTable mapping
- * attribute names to #GVariant values.
+ * Returns: (transfer full): a #GHashTable mapping attribute names to #GVariant values.
  *
  * Since: 1.8
  */
@@ -5975,7 +6048,7 @@ nm_utils_parse_variant_attributes (const char *string,
 	g_return_val_if_fail (key_value_separator, NULL);
 	g_return_val_if_fail (!error || !*error, NULL);
 
-	ht = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
+	ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
 
 	while (TRUE) {
 		gs_free char *name = NULL, *value = NULL;
@@ -6112,7 +6185,7 @@ next:
 
 /*
  * nm_utils_format_variant_attributes:
- * @attributes: (element-type utf8 GVariant): a #GHashTable mapping attribute names to #GVariant values
+ * @attributes:  a #GHashTable mapping attribute names to #GVariant values
  * @attr_separator: the attribute separator character
  * @key_value_separator: character separating key and values
  *
@@ -6134,8 +6207,8 @@ nm_utils_format_variant_attributes (GHashTable *attributes,
 	const char *name, *value;
 	char *escaped;
 	char buf[64];
-	gs_free NMUtilsNamedValue *values = NULL;
-	guint i, len;
+	gs_free_list GList *keys = NULL;
+	GList *iter;
 
 	g_return_val_if_fail (attr_separator, NULL);
 	g_return_val_if_fail (key_value_separator, NULL);
@@ -6143,13 +6216,12 @@ nm_utils_format_variant_attributes (GHashTable *attributes,
 	if (!attributes || !g_hash_table_size (attributes))
 		return NULL;
 
-	values = nm_utils_named_values_from_str_dict (attributes, &len);
-
+	keys = g_list_sort (g_hash_table_get_keys (attributes), (GCompareFunc) g_strcmp0);
 	str = g_string_new ("");
 
-	for (i = 0; i < len; i++) {
-		name = values[i].name;
-		variant = (GVariant *) values[i].value_ptr;
+	for (iter = keys; iter; iter = g_list_next (iter)) {
+		name = iter->data;
+		variant = g_hash_table_lookup (attributes, name);
 		value = NULL;
 
 		if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32))