diff options
| author | Michael Biebl <biebl@debian.org> | 2019-04-21 21:09:51 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2019-04-21 21:09:51 +0200 |
| commit | 85563b7fc7ec2cd21e38debb9b28db342e2e8e7c (patch) | |
| tree | cce7b0b02d28fae2df9fdf2c1804cacd1500f2d7 /shared/nm-std-aux | |
| parent | 9a6dcbf895f9da01768e64b73cec88c16157d91e (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.c | 209 | ||||
| -rw-r--r-- | shared/nm-std-aux/c-list-util.h | 66 | ||||
| -rw-r--r-- | shared/nm-std-aux/nm-dbus-compat.h | 74 | ||||
| -rw-r--r-- | shared/nm-std-aux/unaligned.h | 99 |
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 |