about summary refs log tree commit diff
path: root/src/libnm-glib-aux/nm-shared-utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-glib-aux/nm-shared-utils.h')
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.h248
1 files changed, 198 insertions, 50 deletions
diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h
index 0589eeac..3d8eaced 100644
--- a/src/libnm-glib-aux/nm-shared-utils.h
+++ b/src/libnm-glib-aux/nm-shared-utils.h
@@ -243,11 +243,16 @@ extern const NMIPAddr nm_ip_addr_zero;
 static inline int
 nm_ip_addr_cmp(int addr_family, gconstpointer a, gconstpointer b)
 {
+    /* Note that @a and @b are not required to be full NMIPAddr unions.
+     * Depending on @addr_family, they can also be only in_addr_t or
+     * struct in6_addr. */
     NM_CMP_SELF(a, b);
     NM_CMP_DIRECT_MEMCMP(a, b, nm_utils_addr_family_to_size(addr_family));
     return 0;
 }
 
+int nm_ip_addr_cmp_for_sort(gconstpointer a, gconstpointer b, gpointer user_data);
+
 static inline gboolean
 nm_ip_addr_equal(int addr_family, gconstpointer a, gconstpointer b)
 {
@@ -277,8 +282,15 @@ nm_ip_addr_set(int addr_family, gpointer dst, gconstpointer src)
     nm_assert(dst);
     nm_assert(src);
 
-    /* this MUST use memcpy() (or similar means) to support unaligned src/dst pointers. */
+    /* this MUST use memcpy() to support unaligned src/dst pointers. */
     memcpy(dst, src, nm_utils_addr_family_to_size(addr_family));
+
+    /* Note that @dst is not necessarily a NMIPAddr, it could also be just
+     * an in_addr_t/struct in6_addr. We thus can only set the bytes that
+     * we know are present based on the address family.
+     *
+     * Using this function to initialize an NMIPAddr union (for IPv4) leaves
+     * uninitalized bytes. Avoid that by using nm_ip_addr_init() instead. */
 }
 
 static inline NMIPAddr
@@ -291,6 +303,8 @@ nm_ip_addr_init(int addr_family, gconstpointer src)
 
     G_STATIC_ASSERT_EXPR(sizeof(NMIPAddr) == sizeof(struct in6_addr));
 
+    /* this MUST use memcpy() to support unaligned src/dst pointers. */
+
     if (NM_IS_IPv4(addr_family)) {
         memcpy(&a, src, sizeof(in_addr_t));
 
@@ -312,12 +326,6 @@ gboolean nm_ip_addr_set_from_untrusted(int           addr_family,
 gboolean
 nm_ip_addr_set_from_variant(int addr_family, gpointer dst, GVariant *variant, int *out_addr_family);
 
-static inline gboolean
-nm_ip4_addr_is_localhost(in_addr_t addr4)
-{
-    return (addr4 & htonl(0xFF000000u)) == htonl(0x7F000000u);
-}
-
 static inline gconstpointer
 nm_ip_addr_from_packed_array(int addr_family, gconstpointer ipaddr_arr, gsize idx)
 {
@@ -389,6 +397,17 @@ gboolean nm_utils_get_ipv6_interface_identifier(NMLinkType          link_type,
 
 /*****************************************************************************/
 
+static inline guint32
+_nm_utils_ip4_netmask_to_prefix(in_addr_t subnetmask)
+{
+    G_STATIC_ASSERT_EXPR(__SIZEOF_INT__ == 4);
+    G_STATIC_ASSERT_EXPR(sizeof(int) == 4);
+    G_STATIC_ASSERT_EXPR(sizeof(guint) == 4);
+    G_STATIC_ASSERT_EXPR(sizeof(subnetmask) == 4);
+
+    return ((subnetmask != 0u) ? (guint32) (32 - __builtin_ctz(ntohl(subnetmask))) : 0u);
+}
+
 /**
  * _nm_utils_ip4_prefix_to_netmask:
  * @prefix: a CIDR prefix
@@ -485,11 +504,20 @@ nm_utils_ip_address_same_prefix(int           addr_family,
 /*****************************************************************************/
 
 gboolean nm_utils_ip_is_site_local(int addr_family, const void *address);
+gboolean nm_utils_ip6_is_ula(const struct in6_addr *address);
 
 /*****************************************************************************/
 
-#define NM_IPV4LL_NETWORK ((in_addr_t) (htonl(0xA9FE0000lu)))
-#define NM_IPV4LL_NETMASK ((in_addr_t) (htonl(0xFFFF0000lu)))
+#define NM_IPV4LL_NETWORK ((in_addr_t) htonl(0xA9FE0000lu))
+#define NM_IPV4LL_NETMASK ((in_addr_t) htonl(0xFFFF0000lu))
+
+static inline gboolean
+nm_utils_ip4_address_is_loopback(in_addr_t addr)
+{
+    /* There is also IN_LOOPBACK() in <linux/in.h>, but there the
+     * argument is in host order not `in_addr_t`. */
+    return (addr & htonl(0xFF000000u)) == htonl(0x7F000000u);
+}
 
 static inline gboolean
 nm_utils_ip4_address_is_link_local(in_addr_t addr)
@@ -1987,6 +2015,7 @@ typedef struct {
         NMUtilsNamedEntry named_entry;
         const char       *name;
         char             *name_mutable;
+        gpointer          name_ptr;
     };
     union {
         const char *value_str;
@@ -2000,14 +2029,28 @@ typedef struct {
         .name = (n), .value_ptr = (v)   \
     }
 
-NMUtilsNamedValue *
-nm_utils_named_values_from_strdict_full(GHashTable         *hash,
-                                        guint              *out_len,
-                                        GCompareDataFunc    compare_func,
-                                        gpointer            user_data,
-                                        NMUtilsNamedValue  *provided_buffer,
-                                        guint               provided_buffer_len,
-                                        NMUtilsNamedValue **out_allocated_buffer);
+NMUtilsNamedValue *nm_utils_hash_to_array_full(GHashTable         *hash,
+                                               guint              *out_len,
+                                               GCompareDataFunc    compare_func,
+                                               gpointer            user_data,
+                                               NMUtilsNamedValue  *provided_buffer,
+                                               guint               provided_buffer_len,
+                                               NMUtilsNamedValue **out_allocated_buffer);
+
+#define nm_utils_named_values_from_strdict_full(hash,                 \
+                                                out_len,              \
+                                                compare_func,         \
+                                                user_data,            \
+                                                provided_buffer,      \
+                                                provided_buffer_len,  \
+                                                out_allocated_buffer) \
+    nm_utils_hash_to_array_full((hash),                               \
+                                (out_len),                            \
+                                (compare_func),                       \
+                                (user_data),                          \
+                                (provided_buffer),                    \
+                                (provided_buffer_len),                \
+                                (out_allocated_buffer))
 
 #define nm_utils_named_values_from_strdict(hash, out_len, array, out_allocated_buffer) \
     nm_utils_named_values_from_strdict_full((hash),                                    \
@@ -2048,6 +2091,29 @@ gpointer *nm_utils_hash_values_to_array(GHashTable      *hash,
                                         gpointer         user_data,
                                         guint           *out_len);
 
+static inline NMUtilsNamedValue *
+nm_utils_hash_to_array(GHashTable      *hash,
+                       GCompareDataFunc compare_func,
+                       gpointer         user_data,
+                       guint           *out_len)
+{
+    return nm_utils_hash_to_array_full(hash, out_len, compare_func, user_data, NULL, 0, NULL);
+}
+
+#define nm_utils_hash_to_array_with_buffer(hash,                 \
+                                           out_len,              \
+                                           compare_func,         \
+                                           user_data,            \
+                                           array,                \
+                                           out_allocated_buffer) \
+    nm_utils_hash_to_array_full((hash),                          \
+                                (out_len),                       \
+                                (compare_func),                  \
+                                (user_data),                     \
+                                (array),                         \
+                                G_N_ELEMENTS(array),             \
+                                (out_allocated_buffer))
+
 static inline const char **
 nm_strdict_get_keys(const GHashTable *hash, gboolean sorted, guint *out_length)
 {
@@ -2156,38 +2222,57 @@ nm_g_array_unref(GArray *arr)
         g_array_unref(arr);
 }
 
-#define nm_g_array_first(arr, type)   \
-    ({                                \
-        GArray *const _arr = (arr);   \
-        guint         _len;           \
-                                      \
-        nm_assert(_arr);              \
-        _len = _arr->len;             \
-        nm_assert(_len > 0);          \
-        &g_array_index(arr, type, 0); \
+#define nm_g_array_first(arr, Type)                                \
+    ({                                                             \
+        GArray *const _arr = (arr);                                \
+                                                                   \
+        nm_assert(_arr);                                           \
+        nm_assert(sizeof(Type) == g_array_get_element_size(_arr)); \
+        nm_assert(_arr->len > 0);                                  \
+                                                                   \
+        &g_array_index(arr, Type, 0);                              \
     })
 
-#define nm_g_array_last(arr, type)            \
-    ({                                        \
-        GArray *const _arr = (arr);           \
-        guint         _len;                   \
-                                              \
-        nm_assert(_arr);                      \
-        _len = _arr->len;                     \
-        nm_assert(_len > 0);                  \
-        &g_array_index(arr, type, _len - 1u); \
+#define nm_g_array_last(arr, Type)                                 \
+    ({                                                             \
+        GArray *const _arr = (arr);                                \
+                                                                   \
+        nm_assert(_arr);                                           \
+        nm_assert(sizeof(Type) == g_array_get_element_size(_arr)); \
+        nm_assert(_arr->len > 0);                                  \
+                                                                   \
+        &g_array_index(arr, Type, _arr->len - 1u);                 \
+    })
+
+/* Similar to g_array_index(). The differences are
+ * - this does nm_assert() checks that the arguments are valid.
+ * - returns a pointer to the element. */
+#define nm_g_array_index_p(arr, Type, idx)                            \
+    ({                                                                \
+        GArray *const _arr_55 = (arr);                                \
+        const guint   _idx_55 = (idx);                                \
+                                                                      \
+        nm_assert(_arr_55);                                           \
+        nm_assert(sizeof(Type) == g_array_get_element_size(_arr_55)); \
+        nm_assert(_idx_55 < _arr_55->len);                            \
+                                                                      \
+        &g_array_index(_arr_55, Type, _idx_55);                       \
     })
 
-#define nm_g_array_append_new(arr, type)   \
-    ({                                     \
-        GArray *const _arr = (arr);        \
-        guint         _len;                \
-                                           \
-        nm_assert(_arr);                   \
-        _len = _arr->len;                  \
-        nm_assert(_len < G_MAXUINT);       \
-        g_array_set_size(_arr, _len + 1u); \
-        &g_array_index(arr, type, _len);   \
+#define nm_g_array_append_new(arr, Type)                           \
+    ({                                                             \
+        GArray *const _arr = (arr);                                \
+        guint         _len;                                        \
+                                                                   \
+        nm_assert(_arr);                                           \
+        nm_assert(sizeof(Type) == g_array_get_element_size(_arr)); \
+                                                                   \
+        _len = _arr->len;                                          \
+                                                                   \
+        nm_assert(_len < G_MAXUINT);                               \
+                                                                   \
+        g_array_set_size(_arr, _len + 1u);                         \
+        &g_array_index(arr, Type, _len);                           \
     })
 
 /*****************************************************************************/
@@ -2794,6 +2879,8 @@ nm_ether_addr_to_string(const NMEtherAddr *ether_addr, char sbuf[static(sizeof(N
 #define nm_ether_addr_to_string_a(ether_addr) \
     nm_ether_addr_to_string((ether_addr), g_alloca(sizeof(NMEtherAddr) * 3))
 
+NMEtherAddr *nm_ether_addr_from_string(NMEtherAddr *addr, const char *str);
+
 guint8 *nm_utils_hexstr2bin_full(const char *hexstr,
                                  gboolean    allow_0x_prefix,
                                  gboolean    delimiter_required,
@@ -3083,10 +3170,14 @@ gboolean nm_utils_ifname_valid(const char *name, NMUtilsIfaceType type, GError *
 static inline GArray *
 nm_strvarray_ensure(GArray **p)
 {
+    nm_assert(p);
+
     if (!*p) {
         *p = g_array_new(TRUE, FALSE, sizeof(char *));
         g_array_set_clear_func(*p, nm_indirect_g_free);
-    }
+    } else
+        nm_assert(g_array_get_element_size(*p) == sizeof(char *));
+
     return *p;
 }
 
@@ -3095,6 +3186,9 @@ nm_strvarray_add(GArray *array, const char *str)
 {
     char *s;
 
+    nm_assert(array);
+    nm_assert(g_array_get_element_size(array) == sizeof(char *));
+
     s = g_strdup(str);
     g_array_append_val(array, s);
 }
@@ -3102,15 +3196,14 @@ nm_strvarray_add(GArray *array, const char *str)
 static inline const char *
 nm_strvarray_get_idx(GArray *array, guint idx)
 {
-    nm_assert(array);
-    nm_assert(idx < array->len);
-
-    return g_array_index(array, const char *, idx);
+    return *nm_g_array_index_p(array, const char *, idx);
 }
 
 static inline const char *const *
 nm_strvarray_get_strv_non_empty(GArray *arr, guint *length)
 {
+    nm_assert(!arr || g_array_get_element_size(arr) == sizeof(char *));
+
     if (!arr || arr->len == 0) {
         NM_SET_OUT(length, 0);
         return NULL;
@@ -3125,6 +3218,8 @@ nm_strvarray_get_strv_non_empty_dup(GArray *arr, guint *length)
 {
     const char *const *strv;
 
+    nm_assert(!arr || g_array_get_element_size(arr) == sizeof(char *));
+
     if (!arr || arr->len == 0) {
         NM_SET_OUT(length, 0);
         return NULL;
@@ -3143,6 +3238,8 @@ nm_strvarray_get_strv(GArray **arr, guint *length)
         return (const char *const *) arr;
     }
 
+    nm_assert(g_array_get_element_size(*arr) == sizeof(char *));
+
     NM_SET_OUT(length, (*arr)->len);
     return &g_array_index(*arr, const char *, 0);
 }
@@ -3154,6 +3251,8 @@ nm_strvarray_set_strv(GArray **array, const char *const *strv)
 
     array_old = g_steal_pointer(array);
 
+    nm_assert(!array_old || g_array_get_element_size(array_old) == sizeof(char *));
+
     if (!strv || !strv[0])
         return;
 
@@ -3170,6 +3269,7 @@ nm_strvarray_find_first(GArray *strv, const char *needle)
     nm_assert(needle);
 
     if (strv) {
+        nm_assert(g_array_get_element_size(strv) == sizeof(char *));
         for (i = 0; i < strv->len; i++) {
             if (nm_streq(needle, g_array_index(strv, const char *, i)))
                 return i;
@@ -3253,6 +3353,12 @@ char *_nm_utils_format_variant_attributes(GHashTable                          *a
 
 /*****************************************************************************/
 
+/* glibc defines HOST_NAME_MAX as 64. Also Linux' sethostname() enforces
+ * that (__NEW_UTS_LEN). However, musl sets this to 255.
+ *
+ * At some places, we want to follow Linux. Hardcode our own define. */
+#define NM_HOST_NAME_MAX 64
+
 gboolean nm_utils_is_localhost(const char *name);
 
 gboolean nm_utils_is_specific_hostname(const char *name);
@@ -3305,4 +3411,46 @@ gboolean nm_utils_validate_hostname(const char *hostname);
 
 void nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify);
 
+/*****************************************************************************/
+
+int nm_unbase64char(char c);
+int nm_unbase64mem_full(const char *p, gsize l, gboolean secure, guint8 **ret, gsize *ret_size);
+
+/*****************************************************************************/
+
+static inline gboolean
+nm_path_is_absolute(const char *p)
+{
+    /* Copied from systemd's path_is_absolute()
+     * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.h#L50 */
+
+    nm_assert(p);
+    return p[0] == '/';
+}
+
+int nm_path_find_first_component(const char **p, gboolean accept_dot_dot, const char **ret);
+
+int nm_path_compare(const char *a, const char *b);
+
+static inline gboolean
+nm_path_equal(const char *a, const char *b)
+{
+    return nm_path_compare(a, b) == 0;
+}
+
+char *nm_path_simplify(char *path);
+
+char *
+nm_path_startswith_full(const char *path, const char *prefix, gboolean accept_dot_dot) _nm_pure;
+
+static inline char *
+nm_path_startswith(const char *path, const char *prefix)
+{
+    return nm_path_startswith_full(path, prefix, TRUE);
+}
+
+/*****************************************************************************/
+
+gboolean nm_hostname_is_valid(const char *s, gboolean trailing_dot);
+
 #endif /* __NM_SHARED_UTILS_H__ */