diff options
| author | Michael Biebl <biebl@debian.org> | 2017-05-11 14:55:55 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2017-05-11 14:55:55 +0200 |
| commit | c333f062ddcba9b35330647bf6cbd0a07f2d786e (patch) | |
| tree | 257c3a0c74c09f4ad2328eab5b932806405f0c1c /shared/nm-utils | |
| parent | a222e56e103f949b148a6942e385ccca2c26d9f3 (diff) | |
New upstream version 1.8.0 upstream/1.8.0
Diffstat (limited to 'shared/nm-utils')
| -rw-r--r-- | shared/nm-utils/nm-glib.h | 8 | ||||
| -rw-r--r-- | shared/nm-utils/nm-macros-internal.h | 160 | ||||
| -rw-r--r-- | shared/nm-utils/nm-shared-utils.c | 50 | ||||
| -rw-r--r-- | shared/nm-utils/nm-shared-utils.h | 4 | ||||
| -rw-r--r-- | shared/nm-utils/nm-test-utils.h | 151 | ||||
| -rw-r--r-- | shared/nm-utils/nm-udev-utils.c | 292 | ||||
| -rw-r--r-- | shared/nm-utils/nm-udev-utils.h | 48 |
7 files changed, 608 insertions, 105 deletions
diff --git a/shared/nm-utils/nm-glib.h b/shared/nm-utils/nm-glib.h index 03251ca0..dd18756a 100644 --- a/shared/nm-utils/nm-glib.h +++ b/shared/nm-utils/nm-glib.h @@ -134,7 +134,7 @@ __g_type_ensure (GType type) /* Rumtime check for glib version. First do a compile time check which * (if satisfied) shortcuts the runtime check. */ -inline static gboolean +static inline gboolean nm_glib_check_version (guint major, guint minor, guint micro) { return GLIB_CHECK_VERSION (major, minor, micro) @@ -147,7 +147,7 @@ nm_glib_check_version (guint major, guint minor, guint micro) } /* g_test_skip() is only available since glib 2.38. Add a compatibility wrapper. */ -inline static void +static inline void __nmtst_g_test_skip (const gchar *msg) { #if GLIB_CHECK_VERSION (2, 38, 0) @@ -162,7 +162,7 @@ __nmtst_g_test_skip (const gchar *msg) /* g_test_add_data_func_full() is only available since glib 2.34. Add a compatibility wrapper. */ -inline static void +static inline void __g_test_add_data_func_full (const char *testpath, gpointer test_data, GTestDataFunc test_func, @@ -278,7 +278,7 @@ _nm_g_ptr_array_insert (GPtrArray *array, #if !GLIB_CHECK_VERSION (2, 40, 0) -inline static gboolean +static inline gboolean _g_key_file_save_to_file (GKeyFile *key_file, const gchar *filename, GError **error) diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 70476b7e..6ca66d29 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -106,12 +106,14 @@ _nm_auto_protect_errno (int *p_saved_errno) #define __NM_UTILS_MACRO_REST_HELPER_ONE(first) #define __NM_UTILS_MACRO_REST_HELPER_TWOORMORE(first, ...) , __VA_ARGS__ #define __NM_UTILS_MACRO_REST_NUM(...) \ - __NM_UTILS_MACRO_REST_SELECT_20TH(__VA_ARGS__, \ + __NM_UTILS_MACRO_REST_SELECT_30TH(__VA_ARGS__, \ + TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\ + TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\ TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\ TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\ TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\ 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 +#define __NM_UTILS_MACRO_REST_SELECT_30TH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, ...) a30 /*****************************************************************************/ @@ -178,7 +180,7 @@ _nm_auto_protect_errno (int *p_saved_errno) /** * NM_G_ERROR_MSG: - * @error: (allow none): the #GError instance + * @error: (allow-none): the #GError instance * * All functions must follow the convention that when they * return a failure, they must also set the GError to a valid @@ -233,21 +235,34 @@ NM_G_ERROR_MSG (GError *error) #define _NM_IN_SET_EVAL_16(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_15 (op, _x, __VA_ARGS__) #define _NM_IN_SET_EVAL_N2(op, _x, n, ...) (_NM_IN_SET_EVAL_##n(op, _x, __VA_ARGS__)) -#define _NM_IN_SET_EVAL_N(op, x, n, ...) \ +#define _NM_IN_SET_EVAL_N(op, type, x, n, ...) \ ({ \ - typeof(x) _x = (x); \ + type _x = (x); \ + \ + /* trigger a -Wenum-compare warning */ \ + nm_assert (TRUE || _x == (x)); \ + \ !!_NM_IN_SET_EVAL_N2(op, _x, n, __VA_ARGS__); \ }) +#define _NM_IN_SET(op, type, x, ...) _NM_IN_SET_EVAL_N(op, type, x, NM_NARG (__VA_ARGS__), __VA_ARGS__) + /* Beware that this does short-circuit evaluation (use "||" instead of "|") * which has a possibly unexpected non-function-like behavior. * Use NM_IN_SET_SE if you need all arguments to be evaluted. */ -#define NM_IN_SET(x, ...) _NM_IN_SET_EVAL_N(||, x, NM_NARG (__VA_ARGS__), __VA_ARGS__) +#define NM_IN_SET(x, ...) _NM_IN_SET(||, typeof (x), x, __VA_ARGS__) /* "SE" stands for "side-effect". Contrary to NM_IN_SET(), this does not do * short-circuit evaluation, which can make a difference if the arguments have * side-effects. */ -#define NM_IN_SET_SE(x, ...) _NM_IN_SET_EVAL_N(|, x, NM_NARG (__VA_ARGS__), __VA_ARGS__) +#define NM_IN_SET_SE(x, ...) _NM_IN_SET(|, typeof (x), x, __VA_ARGS__) + +/* the *_TYPED forms allow to explicitly select the type of "x". This is useful + * if "x" doesn't support typeof (bitfields) or you want to gracefully convert + * a type using automatic type conversion rules (but not forcing the conversion + * with a cast). */ +#define NM_IN_SET_TYPED(type, x, ...) _NM_IN_SET(||, type, x, __VA_ARGS__) +#define NM_IN_SET_SE_TYPED(type, x, ...) _NM_IN_SET(|, type, x, __VA_ARGS__) /*****************************************************************************/ @@ -278,8 +293,8 @@ _NM_IN_STRSET_streq (const char *x, const char *s) #define _NM_IN_STRSET_EVAL_N(op, x, n, ...) \ ({ \ const char *_x = (x); \ - ( ((_x == NULL) && _NM_IN_SET_EVAL_N2 (op, (const char *) NULL, n, __VA_ARGS__)) \ - || ((_x != NULL) && _NM_IN_STRSET_EVAL_N2 (op, _x, n, __VA_ARGS__)) \ + ( ((_x == NULL) && _NM_IN_SET_EVAL_N2 (op, ((const char *) NULL), n, __VA_ARGS__)) \ + || ((_x != NULL) && _NM_IN_STRSET_EVAL_N2 (op, _x, n, __VA_ARGS__)) \ ); \ }) @@ -341,6 +356,40 @@ _NM_IN_STRSET_streq (const char *x, const char *s) /*****************************************************************************/ +/* NM_CACHED_QUARK() returns the GQuark for @string, but caches + * it in a static variable to speed up future lookups. + * + * @string must be a string literal. + */ +#define NM_CACHED_QUARK(string) \ + ({ \ + static GQuark _nm_cached_quark = 0; \ + \ + (G_LIKELY (_nm_cached_quark != 0) \ + ? _nm_cached_quark \ + : (_nm_cached_quark = g_quark_from_static_string (""string""))); \ + }) + +/* NM_CACHED_QUARK_FCN() is essentially the same as G_DEFINE_QUARK + * with two differences: + * - @string must be a quited string-literal + * - @fcn must be the full function name, while G_DEFINE_QUARK() appends + * "_quark" to the function name. + * Both properties of G_DEFINE_QUARK() are non favorable, because you can no + * longer grep for string/fcn -- unless you are aware that you are searching + * for G_DEFINE_QUARK() and omit quotes / append _quark(). With NM_CACHED_QUARK_FCN(), + * ctags/cscope can locate the use of @fcn (though it doesn't recognize that + * NM_CACHED_QUARK_FCN() defines it). + */ +#define NM_CACHED_QUARK_FCN(string, fcn) \ +GQuark \ +fcn (void) \ +{ \ + return NM_CACHED_QUARK (string); \ +} + +/*****************************************************************************/ + #define nm_streq(s1, s2) (strcmp (s1, s2) == 0) #define nm_streq0(s1, s2) (g_strcmp0 (s1, s2) == 0) @@ -435,6 +484,9 @@ _notify (obj_type *obj, _PropertyEnums prop) \ /*****************************************************************************/ +/* these are implemented as a macro, because they accept self + * as both (type*) and (const type*), and return a const + * private pointer accordingly. */ #define __NM_GET_PRIVATE(self, type, is_check, result_cmd) \ ({ \ /* preserve the const-ness of self. Unfortunately, that @@ -442,7 +494,7 @@ _notify (obj_type *obj, _PropertyEnums prop) \ typeof (self) _self = (self); \ \ /* Get compiler error if variable is of wrong type */ \ - _nm_unused const type *_self2 = (_self); \ + _nm_unused const type *const _self2 = (_self); \ \ nm_assert (is_check (_self)); \ ( result_cmd ); \ @@ -451,6 +503,21 @@ _notify (obj_type *obj, _PropertyEnums prop) \ #define _NM_GET_PRIVATE(self, type, is_check) __NM_GET_PRIVATE(self, type, is_check, &_self->_priv) #define _NM_GET_PRIVATE_PTR(self, type, is_check) __NM_GET_PRIVATE(self, type, is_check, _self->_priv) +#define __NM_GET_PRIVATE_VOID(self, type, is_check, result_cmd) \ + ({ \ + /* (self) can be any non-const pointer. It will be cast to "type *". + * We don't explicitly cast but assign first to (void *) which + * will fail if @self is pointing to const. */ \ + void *const _self1 = (self); \ + type *const _self = _self1; \ + \ + nm_assert (is_check (_self)); \ + ( result_cmd ); \ + }) + +#define _NM_GET_PRIVATE_VOID(self, type, is_check) __NM_GET_PRIVATE_VOID(self, type, is_check, &_self->_priv) +#define _NM_GET_PRIVATE_PTR_VOID(self, type, is_check) __NM_GET_PRIVATE_VOID(self, type, is_check, _self->_priv) + /*****************************************************************************/ static inline gpointer @@ -543,16 +610,16 @@ nm_clear_g_cancellable (GCancellable **cancellable) /* Determine whether @x is a power of two (@x being an integer type). * For the special cases @x equals zero or one, it also returns true. - * For negative @x, always returns FALSE. That only applies, if the data - * type of @x is signed. */ + * In case @x being a signed type, for negative @x always return FALSE. */ #define nm_utils_is_power_of_two(x) ({ \ typeof(x) __x = (x); \ \ /* Check if the value is negative. In that case, return FALSE. * The first expression is a compile time constant, depending on whether * the type is signed. The second expression is a clumsy way for (__x >= 0), - * which causes a compiler warning for unsigned types. */ \ - ( ( ((typeof(__x)) -1) > ((typeof(__x)) 0) ) || (__x > 0) || (__x == 0) ) \ + * which otherwise causes a compiler warning for unsigned types. */ \ + ( (((typeof(__x)) -1) > ((typeof(__x)) 0)) \ + || (__x > 0 || __x == 0) ) \ && ((__x & (__x - 1)) == 0); \ }) @@ -561,7 +628,7 @@ nm_clear_g_cancellable (GCancellable **cancellable) /* check if @flags has exactly one flag (@check) set. You should call this * only with @check being a compile time constant and a power of two. */ #define NM_FLAGS_HAS(flags, check) \ - ( (G_STATIC_ASSERT_EXPR ( ((check) != 0) && ((check) & ((check)-1)) == 0 )), (NM_FLAGS_ANY ((flags), (check))) ) + ( G_STATIC_ASSERT_EXPR ((check) > 0 && ((check) & ((check) - 1)) == 0), NM_FLAGS_ANY ((flags), (check)) ) #define NM_FLAGS_ANY(flags, check) ( ( ((flags) & (check)) != 0 ) ? TRUE : FALSE ) #define NM_FLAGS_ALL(flags, check) ( ( ((flags) & (check)) == (check) ) ? TRUE : FALSE ) @@ -714,13 +781,15 @@ nm_cmp_uint32_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_d /*****************************************************************************/ static inline guint -nm_encode_version (guint major, guint minor, guint micro) { +nm_encode_version (guint major, guint minor, guint micro) +{ /* analog to the preprocessor macro NM_ENCODE_VERSION(). */ return (major << 16) | (minor << 8) | micro; } static inline void -nm_decode_version (guint version, guint *major, guint *minor, guint *micro) { +nm_decode_version (guint version, guint *major, guint *minor, guint *micro) +{ *major = (version & 0xFFFF0000u) >> 16; *minor = (version & 0x0000FF00u) >> 8; *micro = (version & 0x000000FFu); @@ -743,35 +812,33 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) { /*****************************************************************************/ /* if @str is NULL, return "(null)". Otherwise, allocate a buffer using - * alloca() of size @bufsize and fill it with @str. @str will be quoted with - * single quote, and in case @str is too long, the final quote will be '^'. */ -#define nm_strquote_a(bufsize, str) \ + * alloca() of and fill it with @str. @str will be quoted with double quote. + * If @str is longer then @trunc_at, the string is truncated and the closing + * quote is instead '^' to indicate truncation. + * + * Thus, the maximum stack allocated buffer will be @trunc_at+3. */ +#define nm_strquote_a(trunc_at, str) \ ({ \ - G_STATIC_ASSERT ((bufsize) >= 6); \ - const gsize _BUFSIZE = (bufsize); \ - const char *const _s = (str); \ - char *_r; \ - gsize _l; \ - gboolean _truncated; \ - \ - nm_assert (_BUFSIZE >= 6); \ + const char *const _str = (str); \ \ - if (_s) { \ - _l = strlen (_s) + 3; \ - if ((_truncated = (_BUFSIZE < _l))) \ - _l = _BUFSIZE; \ - \ - _r = g_alloca (_l); \ - _r[0] = '\''; \ - memcpy (&_r[1], _s, _l - 3); \ - _r[_l - 2] = _truncated ? '^' : '\''; \ - _r[_l - 1] = '\0'; \ - } else \ - _r = "(null)"; \ - _r; \ + (_str \ + ? ({ \ + const gsize _trunc_at = (trunc_at); \ + const gsize _strlen_trunc = NM_MIN (strlen (_str), _trunc_at); \ + char *_buf; \ + \ + _buf = g_alloca (_strlen_trunc + 3); \ + _buf[0] = '"'; \ + memcpy (&_buf[1], _str, _strlen_trunc); \ + _buf[_strlen_trunc + 1] = _str[_strlen_trunc] ? '^' : '"'; \ + _buf[_strlen_trunc + 2] = '\0'; \ + _buf; \ + }) \ + : "(null)"); \ }) -#define nm_sprintf_buf(buf, format, ...) ({ \ +#define nm_sprintf_buf(buf, format, ...) \ + ({ \ char * _buf = (buf); \ int _buf_len; \ \ @@ -788,12 +855,12 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) { ({ \ char *_buf; \ int _buf_len; \ + typeof (n_elements) _n_elements = (n_elements); \ \ - G_STATIC_ASSERT (sizeof (char[MAX ((n_elements), 1)]) == (n_elements)); \ - _buf = g_alloca (n_elements); \ - _buf_len = g_snprintf (_buf, (n_elements), \ + _buf = g_alloca (_n_elements); \ + _buf_len = g_snprintf (_buf, _n_elements, \ ""format"", ##__VA_ARGS__); \ - nm_assert (_buf_len < (n_elements)); \ + nm_assert (_buf_len < _n_elements); \ _buf; \ }) @@ -870,7 +937,6 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) { #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 38bb8181..413526dc 100644 --- a/shared/nm-utils/nm-shared-utils.c +++ b/shared/nm-utils/nm-shared-utils.c @@ -158,6 +158,54 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma /*****************************************************************************/ +/** + * nm_utils_strv_find_first: + * @list: the strv list to search + * @len: the length of the list, or a negative value if @list is %NULL terminated. + * @needle: the value to search for. The search is done using strcmp(). + * + * Searches @list for @needle and returns the index of the first match (based + * on strcmp()). + * + * For convenience, @list has type 'char**' instead of 'const char **'. + * + * Returns: index of first occurrence or -1 if @needle is not found in @list. + */ +gssize +nm_utils_strv_find_first (char **list, gssize len, const char *needle) +{ + gssize i; + + if (len > 0) { + g_return_val_if_fail (list, -1); + + if (!needle) { + /* if we search a list with known length, %NULL is a valid @needle. */ + for (i = 0; i < len; i++) { + if (!list[i]) + return i; + } + } else { + for (i = 0; i < len; i++) { + if (list[i] && !strcmp (needle, list[i])) + return i; + } + } + } else if (len < 0) { + g_return_val_if_fail (needle, -1); + + if (list) { + for (i = 0; list[i]; i++) { + if (strcmp (needle, list[i]) == 0) + return i; + } + } + } + return -1; +} + +/*****************************************************************************/ + gint _nm_utils_ascii_str_to_bool (const char *str, gint default_value) @@ -192,7 +240,7 @@ _nm_utils_ascii_str_to_bool (const char *str, /*****************************************************************************/ -G_DEFINE_QUARK (nm-utils-error-quark, nm_utils_error) +NM_CACHED_QUARK_FCN ("nm-utils-error-quark", nm_utils_error_quark) void nm_utils_error_set_cancelled (GError **error, diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index 5d8a3a86..f1f9f518 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -43,6 +43,10 @@ void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str); /*****************************************************************************/ +gssize nm_utils_strv_find_first (char **list, gssize len, const char *needle); + +/*****************************************************************************/ + 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, diff --git a/shared/nm-utils/nm-test-utils.h b/shared/nm-utils/nm-test-utils.h index 7be7e254..0dfdfce6 100644 --- a/shared/nm-utils/nm-test-utils.h +++ b/shared/nm-utils/nm-test-utils.h @@ -198,7 +198,7 @@ _nmtst_exit (void) \ } -inline static gboolean +static inline gboolean nmtst_initialized (void) { return !!__nmtst_internal.rand0; @@ -219,7 +219,7 @@ nmtst_initialized (void) * * The caller must g_free() the returned argv array. **/ -inline static char ** +static inline char ** nmtst_str_split (char *str, const char *delimiters) { const char *d; @@ -265,7 +265,7 @@ BREAK_INNER_LOOPS: /* free instances allocated by nmtst (especially nmtst_init()) on shutdown * to release memory. After nmtst_free(), the test is uninitialized again. */ -inline static void +static inline void nmtst_free (void) { if (!nmtst_initialized ()) @@ -280,7 +280,7 @@ nmtst_free (void) memset (&__nmtst_internal, 0, sizeof (__nmtst_internal)); } -inline static void +static inline void __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_level, const char *log_domains, gboolean *out_set_logging) { const char *nmtst_debug; @@ -592,21 +592,21 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_ } #ifndef _NMTST_INSIDE_CORE -inline static void +static inline void nmtst_init (int *argc, char ***argv, gboolean assert_logging) { __nmtst_init (argc, argv, assert_logging, NULL, NULL, NULL); } #endif -inline static gboolean +static inline gboolean nmtst_is_debug (void) { g_assert (nmtst_initialized ()); return __nmtst_internal.is_debug; } -inline static gboolean +static inline gboolean nmtst_test_quick (void) { g_assert (nmtst_initialized ()); @@ -656,7 +656,7 @@ struct _NmtstTestData { gpointer args[1]; }; -inline static void +static inline void _nmtst_test_data_unpack (const NmtstTestData *test_data, gsize n_args, ...) { gsize i; @@ -677,7 +677,7 @@ _nmtst_test_data_unpack (const NmtstTestData *test_data, gsize n_args, ...) } #define nmtst_test_data_unpack(test_data, ...) _nmtst_test_data_unpack(test_data, NM_NARG (__VA_ARGS__), ##__VA_ARGS__) -inline static void +static inline void _nmtst_test_data_free (gpointer data) { NmtstTestData *test_data = data; @@ -691,7 +691,7 @@ _nmtst_test_data_free (gpointer data) g_free (test_data); } -inline static void +static inline void _nmtst_add_test_func_full (const char *testpath, GTestDataFunc test_func, NmtstTestDataRelease fcn_release, gsize n_args, ...) { gsize i; @@ -719,14 +719,14 @@ _nmtst_add_test_func_full (const char *testpath, GTestDataFunc test_func, NmtstT /*****************************************************************************/ -inline static GRand * +static inline GRand * nmtst_get_rand0 (void) { g_assert (nmtst_initialized ()); return __nmtst_internal.rand0; } -inline static GRand * +static inline GRand * nmtst_get_rand (void) { g_assert (nmtst_initialized ()); @@ -757,13 +757,13 @@ nmtst_get_rand (void) return __nmtst_internal.rand; } -inline static guint32 +static inline guint32 nmtst_get_rand_int (void) { return g_rand_int (nmtst_get_rand ()); } -inline static gpointer +static inline gpointer nmtst_rand_buf (GRand *rand, gpointer buffer, gsize buffer_length) { guint32 v; @@ -791,7 +791,7 @@ nmtst_rand_buf (GRand *rand, gpointer buffer, gsize buffer_length) return buffer; } -inline static void * +static inline void * nmtst_rand_perm (GRand *rand, void *dst, const void *src, gsize elmt_size, gsize n_elmt) { gsize i, j; @@ -832,7 +832,7 @@ nmtst_rand_perm (GRand *rand, void *dst, const void *src, gsize elmt_size, gsize return dst; } -inline static GSList * +static inline GSList * nmtst_rand_perm_gslist (GRand *rand, GSList *list) { GSList *result; @@ -859,7 +859,7 @@ nmtst_rand_perm_gslist (GRand *rand, GSList *list) /*****************************************************************************/ -inline static gboolean +static inline gboolean _nmtst_main_loop_run_timeout (gpointer user_data) { GMainLoop **p_loop = user_data; @@ -873,7 +873,7 @@ _nmtst_main_loop_run_timeout (gpointer user_data) return G_SOURCE_REMOVE; } -inline static gboolean +static inline gboolean nmtst_main_loop_run (GMainLoop *loop, int timeout_ms) { GSource *source = NULL; @@ -894,7 +894,7 @@ nmtst_main_loop_run (GMainLoop *loop, int timeout_ms) return loopx != NULL; } -inline static void +static inline void _nmtst_main_loop_quit_on_notify (GObject *object, GParamSpec *pspec, gpointer user_data) { GMainLoop *loop = user_data; @@ -908,14 +908,14 @@ _nmtst_main_loop_quit_on_notify (GObject *object, GParamSpec *pspec, gpointer us /*****************************************************************************/ -inline static const char * +static inline const char * nmtst_get_sudo_cmd (void) { g_assert (nmtst_initialized ()); return __nmtst_internal.sudo_cmd; } -inline static void +static inline void nmtst_reexec_sudo (void) { char *str; @@ -945,7 +945,7 @@ nmtst_reexec_sudo (void) /*****************************************************************************/ -inline static gsize +static inline gsize nmtst_find_all_indexes (gpointer *elements, gsize n_elements, gpointer *needles, @@ -987,7 +987,7 @@ next: /*****************************************************************************/ #define __define_nmtst_static(NUM,SIZE) \ -inline static const char * \ +static inline const char * \ nmtst_static_##SIZE##_##NUM (const char *str) \ { \ gsize l; \ @@ -1008,7 +1008,7 @@ __define_nmtst_static(03, 1024) gs_free char *_nmtst_hidden_##uuid = nm_utils_uuid_generate (); \ const char *const uuid = _nmtst_hidden_##uuid -inline static const char * +static inline const char * nmtst_uuid_generate (void) { static char u[37]; @@ -1039,7 +1039,7 @@ nmtst_uuid_generate (void) g_error ("%s:%d: Expects \"%s\" but got \"%s\"", __FILE__, __LINE__, __substr, __str); \ } G_STMT_END -inline static guint32 +static inline guint32 nmtst_inet4_from_string (const char *str) { guint32 addr; @@ -1055,7 +1055,7 @@ nmtst_inet4_from_string (const char *str) return addr; } -inline static const struct in6_addr * +static inline const struct in6_addr * nmtst_inet6_from_string (const char *str) { static struct in6_addr addr; @@ -1071,7 +1071,7 @@ nmtst_inet6_from_string (const char *str) return &addr; } -inline static void +static inline void _nmtst_assert_ip4_address (const char *file, int line, in_addr_t addr, const char *str_expected) { if (nmtst_inet4_from_string (str_expected) != addr) { @@ -1084,7 +1084,7 @@ _nmtst_assert_ip4_address (const char *file, int line, in_addr_t addr, const cha } #define nmtst_assert_ip4_address(addr, str_expected) _nmtst_assert_ip4_address (__FILE__, __LINE__, addr, str_expected) -inline static void +static inline void _nmtst_assert_ip6_address (const char *file, int line, const struct in6_addr *addr, const char *str_expected) { struct in6_addr any = in6addr_any; @@ -1104,9 +1104,9 @@ _nmtst_assert_ip6_address (const char *file, int line, const struct in6_addr *ad #define nmtst_spawn_sync(working_directory, standard_out, standard_err, assert_exit_status, ...) \ __nmtst_spawn_sync (working_directory, standard_out, standard_err, assert_exit_status, ##__VA_ARGS__, NULL) -inline static gint +static inline gint __nmtst_spawn_sync (const char *working_directory, char **standard_out, char **standard_err, int assert_exit_status, ...) G_GNUC_NULL_TERMINATED; -inline static gint +static inline gint __nmtst_spawn_sync (const char *working_directory, char **standard_out, char **standard_err, int assert_exit_status, ...) { gint exit_status = 0; @@ -1154,7 +1154,7 @@ __nmtst_spawn_sync (const char *working_directory, char **standard_out, char **s /*****************************************************************************/ -inline static char * +static inline char * nmtst_file_resolve_relative_path (const char *rel, const char *cwd) { gs_free char *cwd_free = NULL; @@ -1169,7 +1169,7 @@ nmtst_file_resolve_relative_path (const char *rel, const char *cwd) return g_build_filename (cwd, rel, NULL); } -inline static char * +static inline char * nmtst_file_get_contents (const char *filename) { GError *error = NULL; @@ -1185,7 +1185,7 @@ nmtst_file_get_contents (const char *filename) /*****************************************************************************/ -inline static void +static inline void nmtst_file_unlink_if_exists (const char *name) { int errsv; @@ -1199,7 +1199,7 @@ nmtst_file_unlink_if_exists (const char *name) } } -inline static void +static inline void nmtst_file_unlink (const char *name) { int errsv; @@ -1212,7 +1212,7 @@ nmtst_file_unlink (const char *name) } } -inline static void +static inline void _nmtst_auto_unlinkfile (char **p_name) { if (*p_name) { @@ -1225,7 +1225,7 @@ _nmtst_auto_unlinkfile (char **p_name) /*****************************************************************************/ -inline static void +static inline void _nmtst_assert_resolve_relative_path_equals (const char *f1, const char *f2, const char *file, int line) { gs_free char *p1 = NULL, *p2 = NULL; @@ -1244,7 +1244,7 @@ _nmtst_assert_resolve_relative_path_equals (const char *f1, const char *f2, cons /*****************************************************************************/ #ifdef NM_SETTING_IP_CONFIG_H -inline static void +static inline void nmtst_setting_ip_config_add_address (NMSettingIPConfig *s_ip, const char *address, guint prefix) @@ -1267,7 +1267,7 @@ nmtst_setting_ip_config_add_address (NMSettingIPConfig *s_ip, nm_ip_address_unref (addr); } -inline static void +static inline void nmtst_setting_ip_config_add_route (NMSettingIPConfig *s_ip, const char *dest, guint prefix, @@ -1291,11 +1291,55 @@ nmtst_setting_ip_config_add_route (NMSettingIPConfig *s_ip, g_assert (nm_setting_ip_config_add_route (s_ip, route)); nm_ip_route_unref (route); } + +static inline void +nmtst_assert_route_attribute_string (NMIPRoute *route, const char *name, const char *value) +{ + GVariant *variant; + + variant = nm_ip_route_get_attribute (route, name); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)); + g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, value); +} + +static inline void +nmtst_assert_route_attribute_byte (NMIPRoute *route, const char *name, guchar value) +{ + GVariant *variant; + + variant = nm_ip_route_get_attribute (route, name); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE)); + g_assert_cmpint (g_variant_get_byte (variant), ==, value); +} + +static inline void +nmtst_assert_route_attribute_uint32 (NMIPRoute *route, const char *name, guint32 value) +{ + GVariant *variant; + + variant = nm_ip_route_get_attribute (route, name); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)); + g_assert_cmpint (g_variant_get_uint32 (variant), ==, value); +} + +static inline void +nmtst_assert_route_attribute_boolean (NMIPRoute *route, const char *name, gboolean value) +{ + GVariant *variant; + + variant = nm_ip_route_get_attribute (route, name); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN)); + g_assert_cmpint (g_variant_get_boolean (variant), ==, value); +} #endif /* NM_SETTING_IP_CONFIG_H */ #if (defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__)) || (defined(NM_CONNECTION_H)) -inline static NMConnection * +static inline NMConnection * nmtst_clone_connection (NMConnection *connection) { g_assert (NM_IS_CONNECTION (connection)); @@ -1307,7 +1351,7 @@ nmtst_clone_connection (NMConnection *connection) #endif } -inline static NMConnection * +static inline NMConnection * nmtst_create_minimal_connection (const char *id, const char *uuid, const char *type, NMSettingConnection **out_s_con) { NMConnection *con; @@ -1360,7 +1404,7 @@ nmtst_create_minimal_connection (const char *id, const char *uuid, const char *t return con; } -inline static gboolean +static inline gboolean _nmtst_connection_normalize_v (NMConnection *connection, va_list args) { GError *error = NULL; @@ -1390,7 +1434,7 @@ _nmtst_connection_normalize_v (NMConnection *connection, va_list args) return was_modified; } -inline static gboolean +static inline gboolean _nmtst_connection_normalize (NMConnection *connection, ...) { gboolean was_modified; @@ -1405,7 +1449,7 @@ _nmtst_connection_normalize (NMConnection *connection, ...) #define nmtst_connection_normalize(connection, ...) \ _nmtst_connection_normalize(connection, ##__VA_ARGS__, NULL) -inline static NMConnection * +static inline NMConnection * _nmtst_connection_duplicate_and_normalize (NMConnection *connection, ...) { gboolean was_modified; @@ -1422,7 +1466,7 @@ _nmtst_connection_duplicate_and_normalize (NMConnection *connection, ...) #define nmtst_connection_duplicate_and_normalize(connection, ...) \ _nmtst_connection_duplicate_and_normalize(connection, ##__VA_ARGS__, NULL) -inline static void +static inline void nmtst_assert_connection_equals (NMConnection *a, gboolean normalize_a, NMConnection *b, gboolean normalize_b) { gboolean compare; @@ -1481,7 +1525,7 @@ nmtst_assert_connection_equals (NMConnection *a, gboolean normalize_a, NMConnect g_assert (compare); } -inline static void +static inline void nmtst_assert_connection_verifies (NMConnection *con) { /* assert that the connection does verify, it might be normaliziable or not */ @@ -1495,7 +1539,7 @@ nmtst_assert_connection_verifies (NMConnection *con) g_assert (success); } -inline static void +static inline void nmtst_assert_connection_verifies_without_normalization (NMConnection *con) { /* assert that the connection verifies and does not need any normalization */ @@ -1515,7 +1559,7 @@ nmtst_assert_connection_verifies_without_normalization (NMConnection *con) g_assert (!was_modified); } -inline static void +static inline void nmtst_assert_connection_verifies_and_normalizable (NMConnection *con) { /* assert that the connection does verify, but normalization still modifies it */ @@ -1537,7 +1581,7 @@ nmtst_assert_connection_verifies_and_normalizable (NMConnection *con) nmtst_assert_connection_verifies_without_normalization (clone); } -inline static void +static inline void nmtst_assert_connection_verifies_after_normalization (NMConnection *con, GQuark expect_error_domain, gint expect_error_code) @@ -1564,7 +1608,7 @@ nmtst_assert_connection_verifies_after_normalization (NMConnection *con, nmtst_assert_connection_verifies_without_normalization (clone); } -inline static void +static inline void nmtst_assert_connection_unnormalizable (NMConnection *con, GQuark expect_error_domain, gint expect_error_code) @@ -1591,7 +1635,7 @@ nmtst_assert_connection_unnormalizable (NMConnection *con, g_clear_error (&error); } -inline static void +static inline void nmtst_assert_setting_verifies (NMSetting *setting) { /* assert that the setting verifies without an error */ @@ -1606,7 +1650,7 @@ nmtst_assert_setting_verifies (NMSetting *setting) g_assert (success); } -inline static void +static inline void nmtst_assert_setting_verify_fails (NMSetting *setting, GQuark expect_error_domain, gint expect_error_code) @@ -1661,9 +1705,10 @@ nmtst_assert_hwaddr_equals (gconstpointer hwaddr1, gssize hwaddr1_len, const cha nmtst_assert_hwaddr_equals (hwaddr1, hwaddr1_len, expected, __FILE__, __LINE__) #endif + #if defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__) && defined(__NM_KEYFILE_INTERNAL_H__) -inline static NMConnection * +static inline NMConnection * nmtst_create_connection_from_keyfile (const char *keyfile_str, const char *keyfile_name, const char *base_dir) { GKeyFile *keyfile; @@ -1693,7 +1738,7 @@ nmtst_create_connection_from_keyfile (const char *keyfile_str, const char *keyfi #ifdef __NM_CONNECTION_H__ -inline static GVariant * +static inline GVariant * _nmtst_variant_new_vardict (int dummy, ...) { GVariantBuilder builder; diff --git a/shared/nm-utils/nm-udev-utils.c b/shared/nm-utils/nm-udev-utils.c new file mode 100644 index 00000000..5552d592 --- /dev/null +++ b/shared/nm-utils/nm-udev-utils.c @@ -0,0 +1,292 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-udev-utils.c - udev utils functions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-udev-utils.h" + +#include <libudev.h> + +struct _NMPUdevClient { + char **subsystems; + GSource *watch_source; + struct udev *udev; + struct udev_monitor *monitor; + NMUdevClientEvent event_handler; + gpointer event_user_data; +}; + +/*****************************************************************************/ + +gboolean +nm_udev_utils_property_as_boolean (const char *uproperty) +{ + /* taken from g_udev_device_get_property_as_boolean() */ + + if (uproperty) { + if ( strcmp (uproperty, "1") == 0 + || g_ascii_strcasecmp (uproperty, "true") == 0) + return TRUE; + } + return FALSE; +} + +const char * +nm_udev_utils_property_decode (const char *uproperty, char **to_free) +{ + const char *p; + char *unescaped = NULL; + char *n = NULL; + + if (!uproperty) { + *to_free = NULL; + return NULL; + } + + p = uproperty; + while (*p) { + int a, b; + + if ( p[0] == '\\' + && p[1] == 'x' + && (a = g_ascii_xdigit_value (p[2])) >= 0 + && (b = g_ascii_xdigit_value (p[3])) >= 0) { + if (!unescaped) { + gssize l = p - uproperty; + + unescaped = g_malloc (l + strlen (p) + 1 - 3); + memcpy (unescaped, uproperty, l); + n = &unescaped[l]; + } + *n++ = (a << 4) | b; + p += 4; + } else { + if (n) + *n++ = *p; + p++; + } + } + + if (!unescaped) { + *to_free = NULL; + return uproperty; + } + + return (*to_free = unescaped); +} + +char * +nm_udev_utils_property_decode_cp (const char *uproperty) +{ + char *cpy; + + uproperty = nm_udev_utils_property_decode (uproperty, &cpy); + return cpy ?: g_strdup (uproperty); +} + +/*****************************************************************************/ + +static void +_subsystem_split (const char *subsystem_full, + const char **out_subsystem, + const char **out_devtype, + char **to_free) +{ + char *tmp, *s; + + nm_assert (subsystem_full); + nm_assert (out_subsystem); + nm_assert (out_devtype); + nm_assert (to_free); + + s = strstr (subsystem_full, "/"); + if (s) { + tmp = g_strdup (subsystem_full); + s = &tmp[s - subsystem_full]; + *s = '\0'; + *out_subsystem = tmp; + *out_devtype = &s[1]; + *to_free = tmp; + } else { + *out_subsystem = subsystem_full; + *out_devtype = NULL; + *to_free = NULL; + } +} + +static struct udev_enumerate * +nm_udev_utils_enumerate (struct udev *uclient, + const char *const*subsystems) +{ + struct udev_enumerate *enumerate; + guint n; + + enumerate = udev_enumerate_new (uclient); + + if (subsystems) { + for (n = 0; subsystems[n]; n++) { + const char *subsystem; + const char *devtype; + gs_free char *to_free; + + _subsystem_split (subsystems[n], &subsystem, &devtype, &to_free); + + udev_enumerate_add_match_subsystem (enumerate, subsystem); + + if (devtype != NULL) + udev_enumerate_add_match_property (enumerate, "DEVTYPE", devtype); + } + } + + return enumerate; +} + +struct udev * +nm_udev_client_get_udev (NMUdevClient *self) +{ + g_return_val_if_fail (self, NULL); + + return self->udev; +} + +struct udev_enumerate * +nm_udev_client_enumerate_new (NMUdevClient *self) +{ + g_return_val_if_fail (self, NULL); + + return nm_udev_utils_enumerate (self->udev, (const char *const*) self->subsystems); +} + +/*****************************************************************************/ + +static gboolean +monitor_event (GIOChannel *source, + GIOCondition condition, + gpointer user_data) +{ + NMUdevClient *self = user_data; + struct udev_device *udevice; + + if (!self->monitor) + goto out; + + udevice = udev_monitor_receive_device (self->monitor); + if (udevice == NULL) + goto out; + + self->event_handler (self, + udevice, + self->event_user_data); + udev_device_unref (udevice); + +out: + return TRUE; +} + +/** + * nm_udev_client_new: + * @subsystems: the subsystems + * @event_handler: callback for events + * @event_user_data: user-data for @event_handler + * + * Basically, it is g_udev_client_new(), and most notably + * g_udev_client_constructed(). + * + * Returns: a new NMUdevClient instance. + */ +NMUdevClient * +nm_udev_client_new (const char *const*subsystems, + NMUdevClientEvent event_handler, + gpointer event_user_data) +{ + NMUdevClient *self; + GIOChannel *channel; + guint n; + + self = g_slice_new0 (NMUdevClient); + + self->event_handler = event_handler; + self->event_user_data = event_user_data; + self->subsystems = subsystems && subsystems[0] ? g_strdupv ((char **) subsystems) : NULL; + + self->udev = udev_new (); + if (!self->udev) + goto fail; + + /* connect to event source */ + if (self->event_handler) { + self->monitor = udev_monitor_new_from_netlink (self->udev, "udev"); + if (!self->monitor) + goto fail; + + if (self->subsystems) { + /* install subsystem filters to only wake up for certain events */ + for (n = 0; self->subsystems[n]; n++) { + if (self->monitor) { + gs_free char *to_free; + const char *subsystem; + const char *devtype; + + _subsystem_split (self->subsystems[n], &subsystem, &devtype, &to_free); + udev_monitor_filter_add_match_subsystem_devtype (self->monitor, subsystem, devtype); + } + } + + /* listen to events, and buffer them */ + if (self->monitor) { + udev_monitor_enable_receiving (self->monitor); + channel = g_io_channel_unix_new (udev_monitor_get_fd (self->monitor)); + self->watch_source = g_io_create_watch (channel, G_IO_IN); + g_io_channel_unref (channel); + g_source_set_callback (self->watch_source, (GSourceFunc) monitor_event, self, NULL); + g_source_attach (self->watch_source, g_main_context_get_thread_default ()); + g_source_unref (self->watch_source); + } + } + } + + return self; + +fail: + return nm_udev_client_unref (self); +} + +NMUdevClient * +nm_udev_client_unref (NMUdevClient *self) +{ + if (!self) + return NULL; + + if (self->watch_source) { + g_source_destroy (self->watch_source); + self->watch_source = NULL; + } + + udev_monitor_unref (self->monitor); + self->monitor = NULL; + udev_unref (self->udev); + self->udev = NULL; + + g_strfreev (self->subsystems); + + g_slice_free (NMUdevClient, self); + + return NULL; +} diff --git a/shared/nm-utils/nm-udev-utils.h b/shared/nm-utils/nm-udev-utils.h new file mode 100644 index 00000000..911e8a27 --- /dev/null +++ b/shared/nm-utils/nm-udev-utils.h @@ -0,0 +1,48 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-udev-utils.h - udev utils functions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2017 Red Hat, Inc. + */ + +#ifndef __NM_UDEV_UTILS_H__ +#define __NM_UDEV_UTILS_H__ + +struct udev; +struct udev_device; +struct udev_enumerate; + +gboolean nm_udev_utils_property_as_boolean (const char *uproperty); +const char *nm_udev_utils_property_decode (const char *uproperty, char **to_free); +char *nm_udev_utils_property_decode_cp (const char *uproperty); + +typedef struct _NMPUdevClient NMUdevClient; + +typedef void (*NMUdevClientEvent) (NMUdevClient *udev_client, + struct udev_device *udevice, + gpointer event_user_data); + +NMUdevClient *nm_udev_client_new (const char *const*subsystems, + NMUdevClientEvent event_handler, + gpointer event_user_data); + +NMUdevClient *nm_udev_client_unref (NMUdevClient *self); + +struct udev *nm_udev_client_get_udev (NMUdevClient *self); + +struct udev_enumerate *nm_udev_client_enumerate_new (NMUdevClient *self); + +#endif /* __NM_UDEV_UTILS_H__ */ |