summary refs log tree commit diff
path: root/shared/nm-utils
diff options
context:
space:
mode:
Diffstat (limited to 'shared/nm-utils')
-rw-r--r--shared/nm-utils/nm-macros-internal.h172
-rw-r--r--shared/nm-utils/nm-shared-utils.c83
-rw-r--r--shared/nm-utils/nm-shared-utils.h27
-rw-r--r--shared/nm-utils/nm-test-utils.h70
-rw-r--r--shared/nm-utils/nm-vpn-plugin-macros.h32
5 files changed, 362 insertions, 22 deletions
diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h
index de90e3f5..70476b7e 100644
--- a/shared/nm-utils/nm-macros-internal.h
+++ b/shared/nm-utils/nm-macros-internal.h
@@ -28,7 +28,7 @@
 
 #include "nm-glib.h"
 
-/********************************************************/
+/*****************************************************************************/
 
 #define _nm_packed __attribute__ ((packed))
 #define _nm_unused __attribute__ ((unused))
@@ -36,6 +36,8 @@
 #define _nm_const  __attribute__ ((const))
 #define _nm_printf(a,b) __attribute__ ((__format__ (__printf__, a, b)))
 
+#define nm_offsetofend(t,m) (G_STRUCT_OFFSET (t,m) + sizeof (((t *) NULL)->m))
+
 #define nm_auto(fcn) __attribute__ ((cleanup(fcn)))
 
 /**
@@ -85,6 +87,13 @@ _nm_auto_fclose_impl (FILE **pfd)
 }
 #define nm_auto_fclose nm_auto(_nm_auto_fclose_impl)
 
+static inline void
+_nm_auto_protect_errno (int *p_saved_errno)
+{
+	errno = *p_saved_errno;
+}
+#define NM_AUTO_PROTECT_ERRNO(errsv_saved) nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno)
+
 /*****************************************************************************/
 
 /* http://stackoverflow.com/a/11172679 */
@@ -104,7 +113,7 @@ _nm_auto_fclose_impl (FILE **pfd)
                 TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway)
 #define __NM_UTILS_MACRO_REST_SELECT_20TH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, ...) a20
 
-/********************************************************/
+/*****************************************************************************/
 
 /* http://stackoverflow.com/a/2124385/354393 */
 
@@ -129,7 +138,7 @@ _nm_auto_fclose_impl (FILE **pfd)
          19,18,17,16,15,14,13,12,11,10, \
          9,8,7,6,5,4,3,2,1,0
 
-/********************************************************/
+/*****************************************************************************/
 
 #if defined (__GNUC__)
 #define _NM_PRAGMA_WARNING_DO(warning)       G_STRINGIFY(GCC diagnostic ignored warning)
@@ -165,7 +174,7 @@ _nm_auto_fclose_impl (FILE **pfd)
 #define NM_PRAGMA_WARNING_REENABLE
 #endif
 
-/********************************************************/
+/*****************************************************************************/
 
 /**
  * NM_G_ERROR_MSG:
@@ -185,11 +194,16 @@ NM_G_ERROR_MSG (GError *error)
 	return error ? (error->message ? : "(null)") : "(no-error)"; \
 }
 
-/********************************************************/
+/*****************************************************************************/
 
 /* macro to return strlen() of a compile time string. */
 #define NM_STRLEN(str)     ( sizeof ("" str) - 1 )
 
+/* Note: @value is only evaluated when *out_val is present.
+ * Thus,
+ *    NM_SET_OUT (out_str, g_strdup ("hallo"));
+ * does the right thing.
+ */
 #define NM_SET_OUT(out_val, value) \
 	G_STMT_START { \
 		typeof(*(out_val)) *_out_val = (out_val); \
@@ -199,7 +213,7 @@ NM_G_ERROR_MSG (GError *error)
 		} \
 	} G_STMT_END
 
-/********************************************************/
+/*****************************************************************************/
 
 #define _NM_IN_SET_EVAL_1( op, _x, y)           (_x == (y))
 #define _NM_IN_SET_EVAL_2( op, _x, y, ...)      (_x == (y)) op _NM_IN_SET_EVAL_1  (op, _x, __VA_ARGS__)
@@ -235,7 +249,7 @@ NM_G_ERROR_MSG (GError *error)
  * side-effects. */
 #define NM_IN_SET_SE(x, ...)            _NM_IN_SET_EVAL_N(|, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
 
-/********************************************************/
+/*****************************************************************************/
 
 static inline gboolean
 _NM_IN_STRSET_streq (const char *x, const char *s)
@@ -279,6 +293,52 @@ _NM_IN_STRSET_streq (const char *x, const char *s)
  * side-effects. */
 #define NM_IN_STRSET_SE(x, ...)            _NM_IN_STRSET_EVAL_N(|, x, NM_NARG (__VA_ARGS__), __VA_ARGS__)
 
+#define NM_STRCHAR_ALL(str, ch_iter, predicate) \
+	({ \
+		gboolean _val = TRUE; \
+		const char *_str = (str); \
+		\
+		if (_str) { \
+			for (;;) { \
+				const char ch_iter = _str[0]; \
+				\
+				if (ch_iter != '\0') { \
+					if (predicate) {\
+						_str++; \
+						continue; \
+					} \
+					_val = FALSE; \
+				} \
+				break; \
+			} \
+		} \
+		_val; \
+	})
+
+#define NM_STRCHAR_ANY(str, ch_iter, predicate) \
+	({ \
+		gboolean _val = FALSE; \
+		const char *_str = (str); \
+		\
+		if (_str) { \
+			for (;;) { \
+				const char ch_iter = _str[0]; \
+				\
+				if (ch_iter != '\0') { \
+					if (predicate) { \
+						; \
+					} else { \
+						_str++; \
+						continue; \
+					} \
+					_val = TRUE; \
+				} \
+				break; \
+			} \
+		} \
+		_val; \
+	})
+
 /*****************************************************************************/
 
 #define nm_streq(s1, s2)  (strcmp (s1, s2) == 0)
@@ -298,6 +358,25 @@ nm_strdup_not_empty (const char *str)
 	return str && str[0] ? g_strdup (str) : NULL;
 }
 
+static inline char *
+nm_str_realloc (char *str)
+{
+	gs_free char *s = str;
+
+	/* Returns a new clone of @str and frees @str. The point is that @str
+	 * possibly points to a larger chunck of memory. We want to freshly allocate
+	 * a buffer.
+	 *
+	 * We could use realloc(), but that might not do anything or leave
+	 * @str in its memory pool for chunks of a different size (bad for
+	 * fragmentation).
+	 *
+	 * This is only useful when we want to keep the buffer around for a long
+	 * time and want to re-allocate a more optimal buffer. */
+
+	return g_strdup (s);
+}
+
 /*****************************************************************************/
 
 #define NM_PRINT_FMT_QUOTED(cond, prefix, str, suffix, str_else) \
@@ -526,6 +605,18 @@ _NM_BACKPORT_SYMBOL_IMPL(VERSION, RETURN_TYPE, FUNC, _##FUNC##_##VERSION, ARGS_T
 
 /*****************************************************************************/
 
+#define nm_str_skip_leading_spaces(str) \
+	({ \
+		typeof (*(str)) *_str = (str); \
+		_nm_unused const char *_str_type_check = _str; \
+		\
+		if (_str) { \
+			while (g_ascii_isspace (_str[0])) \
+				_str++; \
+		} \
+		_str; \
+	})
+
 static inline char *
 nm_strstrip (char *str)
 {
@@ -563,6 +654,19 @@ nm_strcmp_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data)
 	return strcmp (s1, s2);
 }
 
+static inline int
+nm_cmp_uint32_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data)
+{
+	const guint32 a = *((const guint32 *) p_a);
+	const guint32 b = *((const guint32 *) p_b);
+
+	if (a < b)
+		return -1;
+	if (a > b)
+		return 1;
+	return 0;
+}
+
 /*****************************************************************************/
 
 /* Taken from systemd's UNIQ_T and UNIQ macros. */
@@ -621,6 +725,21 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) {
 	*minor = (version & 0x0000FF00u) >>  8;
 	*micro = (version & 0x000000FFu);
 }
+
+/*****************************************************************************/
+
+/* taken from systemd's DECIMAL_STR_MAX()
+ *
+ * Returns the number of chars needed to format variables of the
+ * specified type as a decimal string. Adds in extra space for a
+ * negative '-' prefix (hence works correctly on signed
+ * types). Includes space for the trailing NUL. */
+#define NM_DECIMAL_STR_MAX(type) \
+    (2+(sizeof(type) <= 1 ? 3 : \
+        sizeof(type) <= 2 ? 5 : \
+        sizeof(type) <= 4 ? 10 : \
+        sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)])))
+
 /*****************************************************************************/
 
 /* if @str is NULL, return "(null)". Otherwise, allocate a buffer using
@@ -654,23 +773,27 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) {
 
 #define nm_sprintf_buf(buf, format, ...) ({ \
 		char * _buf = (buf); \
+		int _buf_len; \
 		\
 		/* some static assert trying to ensure that the buffer is statically allocated.
 		 * It disallows a buffer size of sizeof(gpointer) to catch that. */ \
 		G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) != sizeof (char *)); \
-		g_snprintf (_buf, sizeof (buf), \
-		            ""format"", ##__VA_ARGS__); \
+		_buf_len = g_snprintf (_buf, sizeof (buf), \
+		                       ""format"", ##__VA_ARGS__); \
+		nm_assert (_buf_len < sizeof (buf)); \
 		_buf; \
 	})
 
 #define nm_sprintf_bufa(n_elements, format, ...) \
 	({ \
 		char *_buf; \
+		int _buf_len; \
 		\
 		G_STATIC_ASSERT (sizeof (char[MAX ((n_elements), 1)]) == (n_elements)); \
 		_buf = g_alloca (n_elements); \
-		g_snprintf (_buf, n_elements, \
-		            ""format"", ##__VA_ARGS__); \
+		_buf_len = g_snprintf (_buf, (n_elements), \
+		                       ""format"", ##__VA_ARGS__); \
+		nm_assert (_buf_len < (n_elements)); \
 		_buf; \
 	})
 
@@ -721,6 +844,33 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) {
 #define false   0
 #endif
 
+
+#ifdef _G_BOOLEAN_EXPR
+/* g_assert() uses G_LIKELY(), which in turn uses _G_BOOLEAN_EXPR().
+ * As glib's implementation uses a local variable _g_boolean_var_,
+ * we cannot do
+ *   g_assert (some_macro ());
+ * where some_macro() itself expands to ({g_assert(); ...}).
+ * In other words, you cannot have a g_assert() inside a g_assert()
+ * without getting a -Werror=shadow failure.
+ *
+ * Workaround that by re-defining _G_BOOLEAN_EXPR()
+ **/
+#undef  _G_BOOLEAN_EXPR
+#define __NM_G_BOOLEAN_EXPR_IMPL(v, expr) \
+	({ \
+		int NM_UNIQ_T(V, v); \
+		\
+		if (expr) \
+			NM_UNIQ_T(V, v) = 1; \
+		else \
+			NM_UNIQ_T(V, v) = 0; \
+		NM_UNIQ_T(V, v); \
+	})
+#define _G_BOOLEAN_EXPR(expr) __NM_G_BOOLEAN_EXPR_IMPL (NM_UNIQ, expr)
+#endif
+
+
 /*****************************************************************************/
 
 #endif /* __NM_MACROS_INTERNAL_H__ */
diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c
index 38f6529d..38bb8181 100644
--- a/shared/nm-utils/nm-shared-utils.c
+++ b/shared/nm-utils/nm-shared-utils.c
@@ -27,6 +27,85 @@
 
 /*****************************************************************************/
 
+void
+nm_utils_strbuf_append_c (char **buf, gsize *len, char c)
+{
+	switch (*len) {
+	case 0:
+		return;
+	case 1:
+		(*buf)[0] = '\0';
+		*len = 0;
+		(*buf)++;
+		return;
+	default:
+		(*buf)[0] = c;
+		(*buf)[1] = '\0';
+		(*len)--;
+		(*buf)++;
+		return;
+	}
+}
+
+void
+nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str)
+{
+	gsize src_len;
+
+	switch (*len) {
+	case 0:
+		return;
+	case 1:
+		if (!str || !*str) {
+			(*buf)[0] = '\0';
+			return;
+		}
+		(*buf)[0] = '\0';
+		*len = 0;
+		(*buf)++;
+		return;
+	default:
+		if (!str || !*str) {
+			(*buf)[0] = '\0';
+			return;
+		}
+		src_len = g_strlcpy (*buf, str, *len);
+		if (src_len >= *len) {
+			*buf = &(*buf)[*len];
+			*len = 0;
+		} else {
+			*buf = &(*buf)[src_len];
+			*len -= src_len;
+		}
+		return;
+	}
+}
+
+void
+nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
+{
+	char *p = *buf;
+	va_list args;
+	gint retval;
+
+	if (*len == 0)
+		return;
+
+	va_start (args, format);
+	retval = g_vsnprintf (p, *len, format, args);
+	va_end (args);
+
+	if (retval >= *len) {
+		*buf = &p[*len];
+		*len = 0;
+	} else {
+		*buf = &p[retval];
+		*len -= retval;
+	}
+}
+
+/*****************************************************************************/
+
 /* _nm_utils_ascii_str_to_int64:
  *
  * A wrapper for g_ascii_strtoll, that checks whether the whole string
@@ -45,7 +124,7 @@ gint64
 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback)
 {
 	gint64 v;
-	char *s = NULL;
+	const char *s = NULL;
 
 	if (str) {
 		while (g_ascii_isspace (str[0]))
@@ -57,7 +136,7 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma
 	}
 
 	errno = 0;
-	v = g_ascii_strtoll (str, &s, base);
+	v = g_ascii_strtoll (str, (char **) &s, base);
 
 	if (errno != 0)
 		return fallback;
diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h
index cfa8f994..5d8a3a86 100644
--- a/shared/nm-utils/nm-shared-utils.h
+++ b/shared/nm-utils/nm-shared-utils.h
@@ -22,14 +22,33 @@
 #ifndef __NM_SHARED_UTILS_H__
 #define __NM_SHARED_UTILS_H__
 
-/******************************************************************************/
+/*****************************************************************************/
+
+static inline void
+_nm_utils_strbuf_init (char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len)
+{
+	NM_SET_OUT (p_buf_len, len);
+	NM_SET_OUT (p_buf_ptr, buf);
+	buf[0] = '\0';
+}
+
+#define nm_utils_strbuf_init(buf, p_buf_ptr, p_buf_len) \
+	G_STMT_START { \
+		G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) > sizeof (char *)); \
+		_nm_utils_strbuf_init ((buf), sizeof (buf), (p_buf_ptr), (p_buf_len)); \
+	} G_STMT_END
+void nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) _nm_printf (3, 4);
+void nm_utils_strbuf_append_c (char **buf, gsize *len, char c);
+void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str);
+
+/*****************************************************************************/
 
 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:
@@ -54,13 +73,13 @@ void nm_utils_error_set_cancelled (GError **error,
 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/shared/nm-utils/nm-test-utils.h b/shared/nm-utils/nm-test-utils.h
index dba41c4b..7e712dcd 100644
--- a/shared/nm-utils/nm-test-utils.h
+++ b/shared/nm-utils/nm-test-utils.h
@@ -106,12 +106,12 @@
 
 #include "nm-utils.h"
 
-/*******************************************************************************/
+/*****************************************************************************/
 
 #define NMTST_G_RETURN_MSG_S(expr) "*: assertion '"NM_ASSERT_G_RETURN_EXPR(expr)"' failed"
 #define NMTST_G_RETURN_MSG(expr)   NMTST_G_RETURN_MSG_S(#expr)
 
-/*******************************************************************************/
+/*****************************************************************************/
 
 /* general purpose functions that have no dependency on other nmtst functions */
 
@@ -168,7 +168,7 @@
 		g_assert (!(success)); \
 	} G_STMT_END
 
-/*******************************************************************************/
+/*****************************************************************************/
 
 struct __nmtst_internal
 {
@@ -979,6 +979,10 @@ __define_nmtst_static(02, 1024)
 __define_nmtst_static(03, 1024)
 #undef __define_nmtst_static
 
+#define NMTST_UUID_INIT(uuid) \
+	gs_free char *_nmtst_hidden_##uuid = nm_utils_uuid_generate (); \
+	const char *const uuid = _nmtst_hidden_##uuid
+
 inline static const char *
 nmtst_uuid_generate (void)
 {
@@ -1123,7 +1127,7 @@ __nmtst_spawn_sync (const char *working_directory, char **standard_out, char **s
 	return exit_status;
 }
 
-/*******************************************************************************/
+/*****************************************************************************/
 
 inline static char *
 nmtst_file_resolve_relative_path (const char *rel, const char *cwd)
@@ -1140,6 +1144,62 @@ nmtst_file_resolve_relative_path (const char *rel, const char *cwd)
 	return g_build_filename (cwd, rel, NULL);
 }
 
+inline static char *
+nmtst_file_get_contents (const char *filename)
+{
+	GError *error = NULL;
+	gboolean success;
+	char *contents = NULL;
+	gsize len;
+
+	success = g_file_get_contents (filename, &contents, &len, &error);
+	nmtst_assert_success (success && contents, error);
+	g_assert_cmpint (strlen (contents), ==, len);
+	return contents;
+}
+
+/*****************************************************************************/
+
+inline static void
+nmtst_file_unlink_if_exists (const char *name)
+{
+	int errsv;
+
+	g_assert (name && name[0]);
+
+	if (unlink (name) != 0) {
+		errsv = errno;
+		if (errsv != ENOENT)
+			g_error ("nmtst_file_unlink_if_exists(%s): failed with %s", name, strerror (errsv));
+	}
+}
+
+inline static void
+nmtst_file_unlink (const char *name)
+{
+	int errsv;
+
+	g_assert (name && name[0]);
+
+	if (unlink (name) != 0) {
+		errsv = errno;
+		g_error ("nmtst_file_unlink(%s): failed with %s", name, strerror (errsv));
+	}
+}
+
+inline static void
+_nmtst_auto_unlinkfile (char **p_name)
+{
+	if (*p_name) {
+		nmtst_file_unlink (*p_name);
+		nm_clear_g_free (p_name);
+	}
+}
+
+#define nmtst_auto_unlinkfile nm_auto(_nmtst_auto_unlinkfile)
+
+/*****************************************************************************/
+
 inline static void
 _nmtst_assert_resolve_relative_path_equals (const char *f1, const char *f2, const char *file, int line)
 {
@@ -1156,7 +1216,7 @@ _nmtst_assert_resolve_relative_path_equals (const char *f1, const char *f2, cons
 }
 #define nmtst_assert_resolve_relative_path_equals(f1, f2) _nmtst_assert_resolve_relative_path_equals (f1, f2, __FILE__, __LINE__);
 
-/*******************************************************************************/
+/*****************************************************************************/
 
 #ifdef NM_SETTING_IP_CONFIG_H
 inline static void
diff --git a/shared/nm-utils/nm-vpn-plugin-macros.h b/shared/nm-utils/nm-vpn-plugin-macros.h
index 06f5b286..acc549f2 100644
--- a/shared/nm-utils/nm-vpn-plugin-macros.h
+++ b/shared/nm-utils/nm-vpn-plugin-macros.h
@@ -24,6 +24,38 @@
 
 #include <syslog.h>
 
+static inline int
+nm_utils_syslog_coerce_from_nm (int syslog_level)
+{
+	/* NetworkManager uses internally NMLogLevel levels. When spawning
+	 * the VPN plugin, it maps those levels to syslog levels as follows:
+	 *
+	 *  LOGL_INFO = LOG_NOTICE,
+	 *  LOGL_DEBUG = LOG_INFO,
+	 *  LOGL_TRACE = LOG_DEBUG,
+	 *
+	 * However, when actually printing to syslog, we don't want to print messages
+	 * with LOGL_INFO level as LOG_NOTICE, because they are *not* to be highlighted.
+	 *
+	 * In other words: NetworkManager has 3 levels that should not require highlighting:
+	 * LOGL_INFO, LOGL_DEBUG, LOGL_TRACE. syslog on the other hand has only LOG_INFO and LOG_DEBUG.
+	 *
+	 * So, coerce those values before printing to syslog. When you receive the syslog_level
+	 * from NetworkManager, instead of calling
+	 *   syslog(syslog_level, ...)
+	 * you should call
+	 *   syslog(nm_utils_syslog_coerce_from_nm(syslog_level), ...)
+	 */
+	switch (syslog_level) {
+	case LOG_INFO:
+		return LOG_DEBUG;
+	case LOG_NOTICE:
+		return LOG_INFO;
+	default:
+		return syslog_level;
+	}
+}
+
 static inline const char *
 nm_utils_syslog_to_str (int syslog_level)
 {