summary refs log tree commit diff
path: root/shared/nm-std-aux
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-04-21 21:09:51 +0200
committerMichael Biebl <biebl@debian.org>2019-04-21 21:09:51 +0200
commit85563b7fc7ec2cd21e38debb9b28db342e2e8e7c (patch)
treecce7b0b02d28fae2df9fdf2c1804cacd1500f2d7 /shared/nm-std-aux
parent9a6dcbf895f9da01768e64b73cec88c16157d91e (diff)
New upstream version 1.18.0 upstream/1.18.0
Diffstat (limited to 'shared/nm-std-aux')
-rw-r--r--shared/nm-std-aux/c-list-util.c209
-rw-r--r--shared/nm-std-aux/c-list-util.h66
-rw-r--r--shared/nm-std-aux/nm-dbus-compat.h74
-rw-r--r--shared/nm-std-aux/unaligned.h99
4 files changed, 448 insertions, 0 deletions
diff --git a/shared/nm-std-aux/c-list-util.c b/shared/nm-std-aux/c-list-util.c
new file mode 100644
index 00000000..44ca26a5
--- /dev/null
+++ b/shared/nm-std-aux/c-list-util.c
@@ -0,0 +1,209 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2017 Red Hat, Inc.
+ */
+
+#include "c-list-util.h"
+
+/*****************************************************************************/
+
+/**
+ * c_list_relink:
+ * @lst: the head list entry
+ *
+ * Takes an invalid list, that has undefined prev pointers.
+ * Only the next pointers are valid, and the tail's next
+ * pointer points to %NULL instead of the head.
+ *
+ * c_list_relink() fixes the list by updating all prev pointers
+ * and close the circular linking by pointing the tails' next
+ * pointer to @lst.
+ *
+ * The use of this function is to do a bulk update, that lets the
+ * list degredate by not updating the prev pointers. At the end,
+ * the list can be fixed by c_list_relink().
+ */
+void
+c_list_relink (CList *lst)
+{
+	CList *ls, *ls_prev;
+
+	ls_prev = lst;
+	ls = lst->next;
+	do {
+		ls->prev = ls_prev;
+		ls_prev = ls;
+		ls = ls->next;
+	} while (ls);
+	ls_prev->next = lst;
+	lst->prev = ls_prev;
+}
+
+/*****************************************************************************/
+
+static CList *
+_c_list_srt_split (CList *ls)
+{
+	CList *ls2;
+
+	ls2 = ls;
+	ls = ls->next;
+	if (!ls)
+		return NULL;
+	do {
+		ls = ls->next;
+		if (!ls)
+			break;
+		ls = ls->next;
+		ls2 = ls2->next;
+	} while (ls);
+	ls = ls2->next;
+	ls2->next = NULL;
+	return ls;
+}
+
+static CList *
+_c_list_srt_merge (CList *ls1,
+                   CList *ls2,
+                   CListSortCmp cmp,
+                   const void *user_data)
+{
+	CList *ls;
+	CList head;
+
+	ls = &head;
+	for (;;) {
+		/* while invoking the @cmp function, the list
+		 * elements are not properly linked. Don't try to access
+		 * their next/prev pointers. */
+		if (cmp (ls1, ls2, user_data) <= 0) {
+			ls->next = ls1;
+			ls = ls1;
+			ls1 = ls1->next;
+			if (!ls1)
+				break;
+		} else {
+			ls->next = ls2;
+			ls = ls2;
+			ls2 = ls2->next;
+			if (!ls2)
+				break;
+		}
+	}
+	ls->next = ls1 ?: ls2;
+
+	return head.next;
+}
+
+typedef struct {
+	CList *ls1;
+	CList *ls2;
+	char ls1_sorted;
+} SortStack;
+
+static CList *
+_c_list_sort (CList *ls,
+              CListSortCmp cmp,
+              const void *user_data)
+{
+	/* reserve a huge stack-size. We need roughly log2(n) entries, hence this
+	 * is much more we will ever need. We don't guard for stack-overflow either. */
+	SortStack stack_arr[70];
+	SortStack *stack_head = stack_arr;
+
+	stack_arr[0].ls1 = ls;
+
+	/* A simple top-down, non-recursive, stable merge-sort.
+	 *
+	 * Maybe natural merge-sort would be better, to do better for
+	 * partially sorted lists. */
+_split:
+	stack_head[0].ls2 = _c_list_srt_split (stack_head[0].ls1);
+	if (stack_head[0].ls2) {
+		stack_head[0].ls1_sorted = 0;
+		stack_head[1].ls1 = stack_head[0].ls1;
+		stack_head++;
+		goto _split;
+	}
+
+_backtrack:
+	if (stack_head == stack_arr)
+		return stack_arr[0].ls1;
+
+	stack_head--;
+	if (!stack_head[0].ls1_sorted) {
+		stack_head[0].ls1 = stack_head[1].ls1;
+		stack_head[0].ls1_sorted = 1;
+		stack_head[1].ls1 = stack_head[0].ls2;
+		stack_head++;
+		goto _split;
+	}
+
+	stack_head[0].ls1 = _c_list_srt_merge (stack_head[0].ls1, stack_head[1].ls1, cmp, user_data);
+	goto _backtrack;
+}
+
+/**
+ * c_list_sort_headless:
+ * @lst: the list.
+ * @cmp: compare function for sorting. While comparing two
+ *   CList elements, their next/prev pointers are in undefined
+ *   state.
+ * @user_data: user data for @cmp.
+ *
+ * Sorts the list @lst according to @cmp. Contrary to
+ * c_list_sort(), @lst is not the list head but a
+ * valid entry as well. This function returns the new
+ * list head.
+ */
+CList *
+c_list_sort_headless (CList *lst,
+                      CListSortCmp cmp,
+                      const void *user_data)
+{
+	if (!c_list_is_empty (lst)) {
+		lst->prev->next = NULL;
+		lst = _c_list_sort (lst, cmp, user_data);
+		c_list_relink (lst);
+	}
+	return lst;
+}
+
+/**
+ * c_list_sort:
+ * @head: the list head.
+ * @cmp: compare function for sorting. While comparing two
+ *   CList elements, their next/prev pointers are in undefined
+ *   state.
+ * @user_data: user data for @cmp.
+ *
+ * Sorts the list @head according to @cmp.
+ */
+void
+c_list_sort (CList *head,
+             CListSortCmp cmp,
+             const void *user_data)
+{
+	if (   !c_list_is_empty (head)
+	    && head->next->next != head) {
+		head->prev->next = NULL;
+		head->next = _c_list_sort (head->next, cmp, user_data);
+		c_list_relink (head);
+	}
+}
diff --git a/shared/nm-std-aux/c-list-util.h b/shared/nm-std-aux/c-list-util.h
new file mode 100644
index 00000000..648bacc7
--- /dev/null
+++ b/shared/nm-std-aux/c-list-util.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2017 Red Hat, Inc.
+ */
+
+#ifndef __C_LIST_UTIL_H__
+#define __C_LIST_UTIL_H__
+
+#include "c-list/src/c-list.h"
+
+/*****************************************************************************/
+
+void c_list_relink (CList *lst);
+
+typedef int (*CListSortCmp) (const CList *a,
+                             const CList *b,
+                             const void *user_data);
+
+CList *c_list_sort_headless (CList *lst,
+                             CListSortCmp cmp,
+                             const void *user_data);
+
+void c_list_sort (CList *head,
+                  CListSortCmp cmp,
+                  const void *user_data);
+
+/* c_list_length_is:
+ * @list: the #CList list head
+ * @check_len: the length to compare
+ *
+ * Returns: basically the same as (c_list_length (@list) == @check_len),
+ *   but does not require to iterate the entire list first. There is only
+ *   one real use: to find out whether there is exactly one element in the
+ *   list, by passing @check_len as 1.
+ */
+static inline int
+c_list_length_is (const CList *list, unsigned long check_len) {
+	unsigned long n = 0;
+	const CList *iter;
+
+	c_list_for_each (iter, list) {
+		++n;
+		if (n > check_len)
+			return 0;
+	}
+
+	return n == check_len;
+}
+
+#endif /* __C_LIST_UTIL_H__ */
diff --git a/shared/nm-std-aux/nm-dbus-compat.h b/shared/nm-std-aux/nm-dbus-compat.h
new file mode 100644
index 00000000..dd97b5fd
--- /dev/null
+++ b/shared/nm-std-aux/nm-dbus-compat.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * 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 of the License, 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 2015 Red Hat, Inc.
+ */
+
+#ifndef __NM_DBUS_COMPAT_H__
+#define __NM_DBUS_COMPAT_H__
+
+/* Copied from <dbus/dbus-shared.h> */
+
+/* Bus names */
+
+/** The bus name used to talk to the bus itself. */
+#define DBUS_SERVICE_DBUS      "org.freedesktop.DBus"
+
+/* Paths */
+/** The object path used to talk to the bus itself. */
+#define DBUS_PATH_DBUS  "/org/freedesktop/DBus"
+/** The object path used in local/in-process-generated messages. */
+#define DBUS_PATH_LOCAL "/org/freedesktop/DBus/Local"
+
+/* Interfaces, these #define don't do much other than
+ * catch typos at compile time
+ */
+/** The interface exported by the object with #DBUS_SERVICE_DBUS and #DBUS_PATH_DBUS */
+#define DBUS_INTERFACE_DBUS           "org.freedesktop.DBus"
+/** The interface supported by introspectable objects */
+#define DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable"
+/** The interface supported by objects with properties */
+#define DBUS_INTERFACE_PROPERTIES     "org.freedesktop.DBus.Properties"
+/** The interface supported by most dbus peers */
+#define DBUS_INTERFACE_PEER           "org.freedesktop.DBus.Peer"
+
+/** This is a special interface whose methods can only be invoked
+ * by the local implementation (messages from remote apps aren't
+ * allowed to specify this interface).
+ */
+#define DBUS_INTERFACE_LOCAL "org.freedesktop.DBus.Local"
+
+/* Owner flags */
+#define DBUS_NAME_FLAG_ALLOW_REPLACEMENT 0x1 /**< Allow another service to become the primary owner if requested */
+#define DBUS_NAME_FLAG_REPLACE_EXISTING  0x2 /**< Request to replace the current primary owner */
+#define DBUS_NAME_FLAG_DO_NOT_QUEUE      0x4 /**< If we can not become the primary owner do not place us in the queue */
+
+/* Replies to request for a name */
+#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER  1 /**< Service has become the primary owner of the requested name */
+#define DBUS_REQUEST_NAME_REPLY_IN_QUEUE       2 /**< Service could not become the primary owner and has been placed in the queue */
+#define DBUS_REQUEST_NAME_REPLY_EXISTS         3 /**< Service is already in the queue */
+#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER  4 /**< Service is already the primary owner */
+
+/* Replies to releasing a name */
+#define DBUS_RELEASE_NAME_REPLY_RELEASED        1 /**< Service was released from the given name */
+#define DBUS_RELEASE_NAME_REPLY_NON_EXISTENT    2 /**< The given name does not exist on the bus */
+#define DBUS_RELEASE_NAME_REPLY_NOT_OWNER       3 /**< Service is not an owner of the given name */
+
+/* Replies to service starts */
+#define DBUS_START_REPLY_SUCCESS         1 /**< Service was auto started */
+#define DBUS_START_REPLY_ALREADY_RUNNING 2 /**< Service was already running */
+
+#endif  /* __NM_DBUS_COMPAT_H__ */
diff --git a/shared/nm-std-aux/unaligned.h b/shared/nm-std-aux/unaligned.h
new file mode 100644
index 00000000..00c17f87
--- /dev/null
+++ b/shared/nm-std-aux/unaligned.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <endian.h>
+#include <stdint.h>
+
+/* BE */
+
+static inline uint16_t unaligned_read_be16(const void *_u) {
+        const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
+
+        return be16toh(u->x);
+}
+
+static inline uint32_t unaligned_read_be32(const void *_u) {
+        const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
+
+        return be32toh(u->x);
+}
+
+static inline uint64_t unaligned_read_be64(const void *_u) {
+        const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
+
+        return be64toh(u->x);
+}
+
+static inline void unaligned_write_be16(void *_u, uint16_t a) {
+        struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
+
+        u->x = be16toh(a);
+}
+
+static inline void unaligned_write_be32(void *_u, uint32_t a) {
+        struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
+
+        u->x = be32toh(a);
+}
+
+static inline void unaligned_write_be64(void *_u, uint64_t a) {
+        struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
+
+        u->x = be64toh(a);
+}
+
+/* LE */
+
+static inline uint16_t unaligned_read_le16(const void *_u) {
+        const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
+
+        return le16toh(u->x);
+}
+
+static inline uint32_t unaligned_read_le32(const void *_u) {
+        const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
+
+        return le32toh(u->x);
+}
+
+static inline uint64_t unaligned_read_le64(const void *_u) {
+        const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
+
+        return le64toh(u->x);
+}
+
+static inline void unaligned_write_le16(void *_u, uint16_t a) {
+        struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
+
+        u->x = le16toh(a);
+}
+
+static inline void unaligned_write_le32(void *_u, uint32_t a) {
+        struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
+
+        u->x = le32toh(a);
+}
+
+static inline void unaligned_write_le64(void *_u, uint64_t a) {
+        struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
+
+        u->x = le64toh(a);
+}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define unaligned_read_ne16 unaligned_read_be16
+#define unaligned_read_ne32 unaligned_read_be32
+#define unaligned_read_ne64 unaligned_read_be64
+
+#define unaligned_write_ne16 unaligned_write_be16
+#define unaligned_write_ne32 unaligned_write_be32
+#define unaligned_write_ne64 unaligned_write_be64
+#else
+#define unaligned_read_ne16 unaligned_read_le16
+#define unaligned_read_ne32 unaligned_read_le32
+#define unaligned_read_ne64 unaligned_read_le64
+
+#define unaligned_write_ne16 unaligned_write_le16
+#define unaligned_write_ne32 unaligned_write_le32
+#define unaligned_write_ne64 unaligned_write_le64
+#endif