diff options
| author | Michael Biebl <biebl@debian.org> | 2019-12-18 18:29:24 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2019-12-18 18:29:24 +0100 |
| commit | 28028b26b3371756811e95d894f709f4b1207c00 (patch) | |
| tree | 6fe7316fd743b51042db47601a8ef8814b3134ac /shared/nm-glib-aux | |
| parent | e22609983008e1a669196ad64ba3a59ae8c76e0d (diff) | |
New upstream version 1.22.0 upstream/1.22.0
Diffstat (limited to 'shared/nm-glib-aux')
35 files changed, 2288 insertions, 710 deletions
diff --git a/shared/nm-glib-aux/nm-c-list.h b/shared/nm-glib-aux/nm-c-list.h index 7512730d..256dda74 100644 --- a/shared/nm-glib-aux/nm-c-list.h +++ b/shared/nm-glib-aux/nm-c-list.h @@ -1,21 +1,6 @@ -/* 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 2014 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2014 Red Hat, Inc. */ #ifndef __NM_C_LIST_H__ @@ -32,6 +17,12 @@ _what && c_list_contains (list, &_what->member); \ }) +/* iterate over the list backwards. */ +#define nm_c_list_for_each_entry_prev(_iter, _list, _m) \ + for (_iter = c_list_entry ((_list)->prev, __typeof__ (*_iter), _m); \ + &(_iter)->_m != (_list); \ + _iter = c_list_entry ((_iter)->_m.prev, __typeof__ (*_iter), _m)) + /*****************************************************************************/ typedef struct { @@ -88,8 +79,25 @@ nm_c_list_elem_free_all (CList *head, GDestroyNotify free_fcn) nm_c_list_elem_free_full (elem, free_fcn); } +#define nm_c_list_elem_find_first(head, arg, predicate) \ + ({ \ + CList *const _head = (head); \ + NMCListElem *_result = NULL; \ + NMCListElem *_elem; \ + \ + c_list_for_each_entry (_elem, _head, lst) { \ + void *const arg = _elem->data; \ + \ + if (predicate) { \ + _result = _elem; \ + break; \ + } \ + } \ + _result; \ + }) + /** - * nm_c_list_elem_find_first: + * nm_c_list_elem_find_first_ptr: * @head: the @CList head of a list containing #NMCListElem elements. * Note that the head is not itself part of the list. * @needle: the needle pointer. @@ -100,15 +108,9 @@ nm_c_list_elem_free_all (CList *head, GDestroyNotify free_fcn) * Returns: the found list element or %NULL if not found. */ static inline NMCListElem * -nm_c_list_elem_find_first (CList *head, gconstpointer needle) +nm_c_list_elem_find_first_ptr (CList *head, gconstpointer needle) { - NMCListElem *elem; - - c_list_for_each_entry (elem, head, lst) { - if (elem->data == needle) - return elem; - } - return NULL; + return nm_c_list_elem_find_first (head, x, x == needle); } /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-dbus-aux.c b/shared/nm-glib-aux/nm-dbus-aux.c index 083c4fee..75b282bc 100644 --- a/shared/nm-glib-aux/nm-dbus-aux.c +++ b/shared/nm-glib-aux/nm-dbus-aux.c @@ -1,21 +1,6 @@ -/* 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 2019 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2019 Red Hat, Inc. */ #include "nm-default.h" @@ -67,3 +52,315 @@ nm_dbus_connection_call_get_name_owner (GDBusConnection *dbus_connection, _nm_dbus_connection_call_get_name_owner_cb, nm_utils_user_data_pack (user_data, callback)); } + +/*****************************************************************************/ + +static void +_nm_dbus_connection_call_get_all_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + gs_unref_variant GVariant *ret = NULL; + gs_free_error GError *error = NULL; + gpointer orig_user_data; + NMDBusConnectionCallDefaultCb callback; + + nm_utils_user_data_unpack (user_data, &orig_user_data, &callback); + + ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error); + + nm_assert ((!!ret) != (!!error)); + + callback (ret, error, orig_user_data); +} + +void +nm_dbus_connection_call_get_all (GDBusConnection *dbus_connection, + const char *bus_name, + const char *object_path, + const char *interface_name, + int timeout_msec, + GCancellable *cancellable, + NMDBusConnectionCallDefaultCb callback, + gpointer user_data) +{ + nm_assert (callback); + + g_dbus_connection_call (dbus_connection, + bus_name, + object_path, + DBUS_INTERFACE_PROPERTIES, + "GetAll", + g_variant_new ("(s)", interface_name), + G_VARIANT_TYPE ("(a{sv})"), + G_DBUS_CALL_FLAGS_NONE, + timeout_msec, + cancellable, + _nm_dbus_connection_call_get_all_cb, + nm_utils_user_data_pack (user_data, callback)); +} + +/*****************************************************************************/ + +typedef struct { + NMDBusConnectionSignalObjectMangerCb callback; + gpointer user_data; + GDestroyNotify user_data_free_func; +} SubscribeObjectManagerData; + +static void +_subscribe_object_manager_cb (GDBusConnection *connection, + const char *sender_name, + const char *arg_object_path, + const char *interface_name, + const char *signal_name, + GVariant *parameters, + gpointer user_data) +{ + const SubscribeObjectManagerData *d = user_data; + + nm_assert (nm_streq0 (interface_name, DBUS_INTERFACE_OBJECT_MANAGER)); + + if (nm_streq (signal_name, "InterfacesAdded")) { + gs_unref_variant GVariant *interfaces_and_properties = NULL; + const char *object_path; + + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(oa{sa{sv}})"))) + return; + + g_variant_get (parameters, + "(&o@a{sa{sv}})", + &object_path, + &interfaces_and_properties); + + d->callback (object_path, interfaces_and_properties, NULL, d->user_data); + return; + } + + if (nm_streq (signal_name, "InterfacesRemoved")) { + gs_free const char **interfaces = NULL; + const char *object_path; + + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(oas)"))) + return; + + g_variant_get (parameters, + "(&o^a&s)", + &object_path, + &interfaces); + + d->callback (object_path, NULL, interfaces, d->user_data); + return; + } +} + +static void +_subscribe_object_manager_data_free (gpointer ptr) +{ + SubscribeObjectManagerData *d = ptr; + + if (d->user_data_free_func) + d->user_data_free_func (d->user_data); + nm_g_slice_free (d); +} + +guint +nm_dbus_connection_signal_subscribe_object_manager (GDBusConnection *dbus_connection, + const char *service_name, + const char *object_path, + NMDBusConnectionSignalObjectMangerCb callback, + gpointer user_data, + GDestroyNotify user_data_free_func) +{ + SubscribeObjectManagerData *d; + + g_return_val_if_fail (callback, 0); + + d = g_slice_new (SubscribeObjectManagerData); + *d = (SubscribeObjectManagerData) { + .callback = callback, + .user_data = user_data, + .user_data_free_func = user_data_free_func, + }; + + return nm_dbus_connection_signal_subscribe_object_manager_plain (dbus_connection, + service_name, + object_path, + NULL, + _subscribe_object_manager_cb, + d, + _subscribe_object_manager_data_free); +} + +/*****************************************************************************/ + +static void +_nm_dbus_connection_call_get_managed_objects_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + gs_unref_variant GVariant *ret = NULL; + gs_unref_variant GVariant *arg = NULL; + gs_free_error GError *error = NULL; + gpointer orig_user_data; + NMDBusConnectionCallDefaultCb callback; + + nm_utils_user_data_unpack (user_data, &orig_user_data, &callback); + + ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error); + + nm_assert ((!!ret) != (!!error)); + + if (ret) { + nm_assert (g_variant_is_of_type (ret, G_VARIANT_TYPE ("(a{oa{sa{sv}}})"))); + arg = g_variant_get_child_value (ret, 0); + } + + callback (arg, error, orig_user_data); +} + +void +nm_dbus_connection_call_get_managed_objects (GDBusConnection *dbus_connection, + const char *bus_name, + const char *object_path, + GDBusCallFlags flags, + int timeout_msec, + GCancellable *cancellable, + NMDBusConnectionCallDefaultCb callback, + gpointer user_data) +{ + nm_assert (callback); + + g_dbus_connection_call (dbus_connection, + bus_name, + object_path, + DBUS_INTERFACE_OBJECT_MANAGER, + "GetManagedObjects", + NULL, + G_VARIANT_TYPE ("(a{oa{sa{sv}}})"), + flags, + timeout_msec, + cancellable, + _nm_dbus_connection_call_get_managed_objects_cb, + nm_utils_user_data_pack (user_data, callback)); +} + +/*****************************************************************************/ + +static void +_call_finish_cb (GObject *source, + GAsyncResult *result, + gpointer user_data, + gboolean return_void, + gboolean strip_dbus_error) +{ + gs_unref_object GTask *task = user_data; + gs_unref_variant GVariant *ret = NULL; + GError *error = NULL; + + nm_assert (G_IS_DBUS_CONNECTION (source)); + nm_assert (G_IS_TASK (user_data)); + + ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (!ret) { + if (strip_dbus_error) + g_dbus_error_strip_remote_error (error); + g_task_return_error (task, error); + return; + } + + if (!return_void) { + nm_assert (!g_variant_is_of_type (ret, G_VARIANT_TYPE ("()"))); + g_task_return_pointer (task, g_steal_pointer (&ret), (GDestroyNotify) g_variant_unref); + } else { + nm_assert (g_variant_is_of_type (ret, G_VARIANT_TYPE ("()"))); + g_task_return_boolean (task, TRUE); + } +} + +/** + * nm_dbus_connection_call_finish_void_cb: + * + * A default callback to pass as callback to g_dbus_connection_call(). + * + * - user_data must be a GTask, whose reference will be consumed by the + * callback. + * - the return GVariant must be a empty tuple "()". + * - the GTask is returned either with error or TRUE boolean. + */ +void +nm_dbus_connection_call_finish_void_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + _call_finish_cb (source, result, user_data, TRUE, FALSE); +} + +/** + * nm_dbus_connection_call_finish_void_strip_dbus_error_cb: + * + * Like nm_dbus_connection_call_finish_void_cb(). The difference + * is that on error this will first call g_dbus_error_strip_remote_error() on the error. + */ +void +nm_dbus_connection_call_finish_void_strip_dbus_error_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + _call_finish_cb (source, result, user_data, TRUE, TRUE); +} + +/** + * nm_dbus_connection_call_finish_variant_cb: + * + * A default callback to pass as callback to g_dbus_connection_call(). + * + * - user_data must be a GTask, whose reference will be consumed by the + * callback. + * - the return GVariant must not be an empty tuple "()". + * - the GTask is returned either with error or with a pointer containing the GVariant. + */ +void +nm_dbus_connection_call_finish_variant_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + _call_finish_cb (source, result, user_data, FALSE, FALSE); +} + +/** + * nm_dbus_connection_call_finish_variant_strip_dbus_error_cb: + * + * Like nm_dbus_connection_call_finish_variant_strip_dbus_error_cb(). The difference + * is that on error this will first call g_dbus_error_strip_remote_error() on the error. + */ +void +nm_dbus_connection_call_finish_variant_strip_dbus_error_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + _call_finish_cb (source, result, user_data, FALSE, TRUE); +} + +/*****************************************************************************/ + +gboolean +_nm_dbus_error_is (GError *error, ...) +{ + gs_free char *dbus_error = NULL; + const char *name; + va_list ap; + + dbus_error = g_dbus_error_get_remote_error (error); + if (!dbus_error) + return FALSE; + + va_start (ap, error); + while ((name = va_arg (ap, const char *))) { + if (nm_streq (dbus_error, name)) + return TRUE; + } + va_end (ap); + + return FALSE; +} diff --git a/shared/nm-glib-aux/nm-dbus-aux.h b/shared/nm-glib-aux/nm-dbus-aux.h index 271a7d9c..840e23c2 100644 --- a/shared/nm-glib-aux/nm-dbus-aux.h +++ b/shared/nm-glib-aux/nm-dbus-aux.h @@ -1,21 +1,6 @@ -/* 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 2019 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2019 Red Hat, Inc. */ #ifndef __NM_DBUS_AUX_H__ @@ -42,6 +27,12 @@ nm_clear_g_dbus_connection_signal (GDBusConnection *dbus_connection, /*****************************************************************************/ +typedef void (*NMDBusConnectionCallDefaultCb) (GVariant *result, + GError *error, + gpointer user_data); + +/*****************************************************************************/ + static inline void nm_dbus_connection_call_start_service_by_name (GDBusConnection *dbus_connection, const char *name, @@ -91,11 +82,126 @@ typedef void (*NMDBusConnectionCallGetNameOwnerCb) (const char *name_owner, gpointer user_data); void nm_dbus_connection_call_get_name_owner (GDBusConnection *dbus_connection, - const char *service_name, - int timeout_msec, - GCancellable *cancellable, - NMDBusConnectionCallGetNameOwnerCb callback, - gpointer user_data); + const char *service_name, + int timeout_msec, + GCancellable *cancellable, + NMDBusConnectionCallGetNameOwnerCb callback, + gpointer user_data); + +static inline guint +nm_dbus_connection_signal_subscribe_properties_changed (GDBusConnection *dbus_connection, + const char *bus_name, + const char *object_path, + const char *interface_name, + GDBusSignalCallback callback, + gpointer user_data, + GDestroyNotify user_data_free_func) + +{ + nm_assert (bus_name); + + /* it seems that using a non-unique name causes problems that we get signals + * also from unrelated senders. Usually, you are anyway monitoring the name-owner, + * so you should have the unique name at hand. + * + * If not, investigate this, ensure that it works, and lift this restriction. */ + nm_assert (g_dbus_is_unique_name (bus_name)); + + return g_dbus_connection_signal_subscribe (dbus_connection, + bus_name, + DBUS_INTERFACE_PROPERTIES, + "PropertiesChanged", + object_path, + interface_name, + G_DBUS_SIGNAL_FLAGS_NONE, + callback, + user_data, + user_data_free_func); +} + +void nm_dbus_connection_call_get_all (GDBusConnection *dbus_connection, + const char *bus_name, + const char *object_path, + const char *interface_name, + int timeout_msec, + GCancellable *cancellable, + NMDBusConnectionCallDefaultCb callback, + gpointer user_data); + +/*****************************************************************************/ + +static inline guint +nm_dbus_connection_signal_subscribe_object_manager_plain (GDBusConnection *dbus_connection, + const char *service_name, + const char *object_path, + const char *signal_name, + GDBusSignalCallback callback, + gpointer user_data, + GDestroyNotify user_data_free_func) +{ + return g_dbus_connection_signal_subscribe (dbus_connection, + service_name, + DBUS_INTERFACE_OBJECT_MANAGER, + signal_name, + object_path, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + callback, + user_data, + user_data_free_func); +} + +typedef void (*NMDBusConnectionSignalObjectMangerCb) (const char *object_path, + GVariant *added_interfaces_and_properties, + const char *const*removed_interfaces, + gpointer user_data); + +guint nm_dbus_connection_signal_subscribe_object_manager (GDBusConnection *dbus_connection, + const char *service_name, + const char *object_path, + NMDBusConnectionSignalObjectMangerCb callback, + gpointer user_data, + GDestroyNotify user_data_free_func); + +void nm_dbus_connection_call_get_managed_objects (GDBusConnection *dbus_connection, + const char *bus_name, + const char *object_path, + GDBusCallFlags flags, + int timeout_msec, + GCancellable *cancellable, + NMDBusConnectionCallDefaultCb callback, + gpointer user_data); + +/*****************************************************************************/ + +void nm_dbus_connection_call_finish_void_cb (GObject *source, + GAsyncResult *result, + gpointer user_data); + +void nm_dbus_connection_call_finish_void_strip_dbus_error_cb (GObject *source, + GAsyncResult *result, + gpointer user_data); + +void nm_dbus_connection_call_finish_variant_cb (GObject *source, + GAsyncResult *result, + gpointer user_data); + +void nm_dbus_connection_call_finish_variant_strip_dbus_error_cb (GObject *source, + GAsyncResult *result, + gpointer user_data); + +/*****************************************************************************/ + +gboolean _nm_dbus_error_is (GError *error, ...) G_GNUC_NULL_TERMINATED; + +#define nm_dbus_error_is(error, ...) \ + ({ \ + GError *const _error = (error); \ + \ + _error && _nm_dbus_error_is (_error, __VA_ARGS__, NULL); \ + }) + +#define NM_DBUS_ERROR_NAME_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod" /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-dedup-multi.c b/shared/nm-glib-aux/nm-dedup-multi.c index 345062ca..6e23228e 100644 --- a/shared/nm-glib-aux/nm-dedup-multi.c +++ b/shared/nm-glib-aux/nm-dedup-multi.c @@ -1,21 +1,6 @@ -/* 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. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2017 Red Hat, Inc. */ #include "nm-default.h" diff --git a/shared/nm-glib-aux/nm-dedup-multi.h b/shared/nm-glib-aux/nm-dedup-multi.h index ca15c516..6867ae79 100644 --- a/shared/nm-glib-aux/nm-dedup-multi.h +++ b/shared/nm-glib-aux/nm-dedup-multi.h @@ -1,21 +1,6 @@ -/* 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. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2017 Red Hat, Inc. */ #ifndef __NM_DEDUP_MULTI_H__ diff --git a/shared/nm-glib-aux/nm-enum-utils.c b/shared/nm-glib-aux/nm-enum-utils.c index b16267a5..e105a4f5 100644 --- a/shared/nm-glib-aux/nm-enum-utils.c +++ b/shared/nm-glib-aux/nm-enum-utils.c @@ -1,21 +1,6 @@ -/* 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. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -225,7 +210,7 @@ _nm_utils_enum_from_str_full (GType type, char **err_token, const NMUtilsEnumValueInfo *value_infos) { - GTypeClass *klass; + nm_auto_unref_gtypeclass GTypeClass *klass = NULL; gboolean ret = FALSE; int value = 0; gs_free char *str_clone = NULL; @@ -317,7 +302,6 @@ _nm_utils_enum_from_str_full (GType type, NM_SET_OUT (err_token, !ret && s[0] ? g_strdup (s) : NULL); NM_SET_OUT (out_value, ret ? value : 0); - g_type_class_unref (klass); return ret; } diff --git a/shared/nm-glib-aux/nm-enum-utils.h b/shared/nm-glib-aux/nm-enum-utils.h index 20db07cc..d863dabd 100644 --- a/shared/nm-glib-aux/nm-enum-utils.h +++ b/shared/nm-glib-aux/nm-enum-utils.h @@ -1,21 +1,6 @@ -/* 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. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2017 Red Hat, Inc. */ #ifndef __NM_ENUM_UTILS_H__ diff --git a/shared/nm-glib-aux/nm-errno.c b/shared/nm-glib-aux/nm-errno.c index 30eb9a8e..9133d87d 100644 --- a/shared/nm-glib-aux/nm-errno.c +++ b/shared/nm-glib-aux/nm-errno.c @@ -1,21 +1,6 @@ -/* 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. - * - * Copyright 2018 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2018 Red Hat, Inc. */ #include "nm-default.h" diff --git a/shared/nm-glib-aux/nm-errno.h b/shared/nm-glib-aux/nm-errno.h index d77735a7..1d329b25 100644 --- a/shared/nm-glib-aux/nm-errno.h +++ b/shared/nm-glib-aux/nm-errno.h @@ -1,21 +1,6 @@ -/* 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. - * - * Copyright 2018 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2018 Red Hat, Inc. */ #ifndef __NM_ERRNO_H__ diff --git a/shared/nm-glib-aux/nm-glib.h b/shared/nm-glib-aux/nm-glib.h index bdb7ea5b..dfb75bf0 100644 --- a/shared/nm-glib-aux/nm-glib.h +++ b/shared/nm-glib-aux/nm-glib.h @@ -1,19 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0+ /* - * 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 2008 - 2018 Red Hat, Inc. + * Copyright (C) 2008 - 2018 Red Hat, Inc. */ #ifndef __NM_GLIB_H__ @@ -569,6 +556,49 @@ _nm_g_value_unset (GValue *value) #define g_value_unset _nm_g_value_unset #endif +/* G_PID_FORMAT was added only in 2.53.5. Define it ourself. + * + * If this was about "pid_t", we would check SIZEOF_PID_T, and set + * PRIi32/PRIi16, like systemd does. But it's actually about + * GPid, which glib typedefs as an "int". + * + * There is a test_gpid() that check that GPid is really a typedef + * for int. */ +#undef G_PID_FORMAT +#define G_PID_FORMAT "i" + +/*****************************************************************************/ + +#if !GLIB_CHECK_VERSION (2, 57, 2) +#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f)) +#endif + +/*****************************************************************************/ + +/* Glib implements g_atomic_pointer_compare_and_exchange() as a macro. + * For one, to inline the atomic operation and also to perform some type checks + * on the arguments. + * Depending on compiler and glib version, glib passes the arguments as they + * are to __atomic_compare_exchange_n(). Some clang version don't accept const + * pointers there. Reimplement the macro to get that right, but with stronger + * type checks (as we use typeof()). Had one job. */ +static inline gboolean +_g_atomic_pointer_compare_and_exchange (volatile void *atomic, + gconstpointer oldval, + gconstpointer newval) +{ + return g_atomic_pointer_compare_and_exchange ((void **) atomic, (void *) oldval, (void *) newval); +} +#undef g_atomic_pointer_compare_and_exchange +#define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \ + ({ \ + typeof (atomic) const _atomic = (atomic); \ + typeof (*_atomic) const _oldval = (oldval); \ + typeof (*_atomic) const _newval = (newval); \ + \ + _g_atomic_pointer_compare_and_exchange (_atomic, _oldval, _newval); \ + }) + /*****************************************************************************/ #endif /* __NM_GLIB_H__ */ diff --git a/shared/nm-glib-aux/nm-hash-utils.c b/shared/nm-glib-aux/nm-hash-utils.c index a6158269..cd51bbaf 100644 --- a/shared/nm-glib-aux/nm-hash-utils.c +++ b/shared/nm-glib-aux/nm-hash-utils.c @@ -1,21 +1,6 @@ -/* 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. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -201,6 +186,26 @@ nm_pstr_equal (gconstpointer a, gconstpointer b) } guint +nm_pint_hash (gconstpointer p) +{ + const int *s = p; + + if (!s) + return nm_hash_static (298377461u); + return nm_hash_val (1208815757u, *s); +} + +gboolean +nm_pint_equals (gconstpointer a, gconstpointer b) +{ + const int *s1 = a; + const int *s2 = a; + + return s1 == s2 + || (s1 && s2 && *s1 == *s2); +} + +guint nm_pdirect_hash (gconstpointer p) { const void *const*s = p; @@ -221,3 +226,34 @@ nm_pdirect_equal (gconstpointer a, gconstpointer b) && s2 && *s1 == *s2); } + +guint +nm_ppdirect_hash (gconstpointer p) +{ + const void *const*const*s = p; + + if (!s) + return nm_hash_static (396534869u); + if (!*s) + return nm_hash_static (1476102263u); + return nm_direct_hash (**s); +} + +gboolean +nm_ppdirect_equal (gconstpointer a, gconstpointer b) +{ + const void *const*const*s1 = a; + const void *const*const*s2 = b; + + if (s1 == s2) + return TRUE; + if (!s1 || !s2) + return FALSE; + + if (*s1 == *s2) + return TRUE; + if (!*s1 || !*s2) + return FALSE; + + return **s1 == **s2; +} diff --git a/shared/nm-glib-aux/nm-hash-utils.h b/shared/nm-glib-aux/nm-hash-utils.h index aa0a3d7c..21c5e584 100644 --- a/shared/nm-glib-aux/nm-hash-utils.h +++ b/shared/nm-glib-aux/nm-hash-utils.h @@ -1,21 +1,6 @@ -/* 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. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2017 Red Hat, Inc. */ #ifndef __NM_HASH_UTILS_H__ @@ -293,13 +278,29 @@ gboolean nm_pstr_equal (gconstpointer a, gconstpointer b); /*****************************************************************************/ +/* nm_pint_*() are for hashing keys that are pointers to int values, + * that is, "const int *" types. */ + +guint nm_pint_hash (gconstpointer p); +gboolean nm_pint_equals (gconstpointer a, gconstpointer b); + +/*****************************************************************************/ + /* this hashes/compares the pointer value that we point to. Basically, - * (((const void *const*) a) == ((const void *const*) b)). */ + * (*((const void *const*) a) == *((const void *const*) b)). */ guint nm_pdirect_hash (gconstpointer p); gboolean nm_pdirect_equal (gconstpointer a, gconstpointer b); +/* this hashes/compares the direct pointer value by following pointers to + * pointers 2 times. + * (**((const void *const*const*) a) == **((const void *const*const*) b)). */ + +guint nm_ppdirect_hash (gconstpointer p); + +gboolean nm_ppdirect_equal (gconstpointer a, gconstpointer b); + /*****************************************************************************/ #define NM_HASH_OBFUSCATE_PTR_FMT "%016" G_GINT64_MODIFIER "x" @@ -311,15 +312,15 @@ gboolean nm_pdirect_equal (gconstpointer a, gconstpointer b); * * Note that there is a chance that two different pointer values hash to the same obfuscated * value. So beware of that when reviewing logs. However, such a collision is very unlikely. */ -#define nm_hash_obfuscate_ptr(static_seed, val) \ - ({ \ - NMHashState _h; \ - const void *_val_obf_ptr = (val); \ - \ - nm_hash_init (&_h, (static_seed)); \ - nm_hash_update_val (&_h, _val_obf_ptr); \ - nm_hash_complete_u64 (&_h); \ - }) +static inline guint64 +nm_hash_obfuscate_ptr (guint static_seed, gconstpointer val) +{ + NMHashState h; + + nm_hash_init (&h, static_seed); + nm_hash_update_val (&h, val); + return nm_hash_complete_u64 (&h); +} /* if you want to log obfuscated pointer for a certain context (like, NMPRuleManager * logging user-tags), then you are advised to use nm_hash_obfuscate_ptr() with your diff --git a/shared/nm-glib-aux/nm-io-utils.c b/shared/nm-glib-aux/nm-io-utils.c index 23133ec5..ec0cd4c8 100644 --- a/shared/nm-glib-aux/nm-io-utils.c +++ b/shared/nm-glib-aux/nm-io-utils.c @@ -1,21 +1,6 @@ -/* 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 2018 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -32,9 +17,9 @@ /*****************************************************************************/ -_nm_printf (3, 4) +_nm_printf (4, 5) static int -_get_contents_error (GError **error, int errsv, const char *format, ...) +_get_contents_error (GError **error, int errsv, int *out_errsv, const char *format, ...) { nm_assert (NM_ERRNO_NATIVE (errsv)); @@ -53,13 +38,17 @@ _get_contents_error (GError **error, int errsv, const char *format, ...) msg, nm_strerror_native_r (errsv, bstrerr, sizeof (bstrerr))); } - return -errsv; + + nm_assert (errsv > 0); + NM_SET_OUT (out_errsv, errsv); + + return FALSE; } -#define _get_contents_error_errno(error, ...) \ +#define _get_contents_error_errno(error, out_errsv, ...) \ ({ \ int _errsv = (errno); \ \ - _get_contents_error (error, _errsv, __VA_ARGS__); \ + _get_contents_error (error, _errsv, out_errsv, __VA_ARGS__); \ }) static char * @@ -110,21 +99,25 @@ _mem_realloc (char *old, gboolean do_bzero_mem, gsize cur_len, gsize new_len) * the NUL byte. That is, it reads only files up to a length of * @max_length - 1 bytes. * @length: optional output argument of the read file size. + * @out_errsv: (allow-none) (out): on error, a positive errno. or zero. + * @error: + * * * A reimplementation of g_file_get_contents() with a few differences: * - accepts an open fd, instead of a path name. This allows you to * use openat(). * - limits the maximum filesize to max_length. * - * Returns: a negative error code on failure. + * Returns: TRUE on success. */ -int +gboolean nm_utils_fd_get_contents (int fd, gboolean close_fd, gsize max_length, NMUtilsFileGetContentsFlags flags, char **contents, gsize *length, + int *out_errsv, GError **error) { nm_auto_close int fd_keeper = close_fd ? fd : -1; @@ -133,12 +126,14 @@ nm_utils_fd_get_contents (int fd, const bool do_bzero_mem = NM_FLAGS_HAS (flags, NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET); int errsv; - g_return_val_if_fail (fd >= 0, -EINVAL); - g_return_val_if_fail (contents, -EINVAL); - g_return_val_if_fail (!error || !*error, -EINVAL); + g_return_val_if_fail (fd >= 0, FALSE); + g_return_val_if_fail (contents && !*contents, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + + NM_SET_OUT (length, 0); if (fstat (fd, &stat_buf) < 0) - return _get_contents_error_errno (error, "failure during fstat"); + return _get_contents_error_errno (error, out_errsv, "failure during fstat"); if (!max_length) { /* default to a very large size, but not extreme */ @@ -151,23 +146,23 @@ nm_utils_fd_get_contents (int fd, ssize_t n_read; if (n_stat > max_length - 1) - return _get_contents_error (error, EMSGSIZE, "file too large (%zu+1 bytes with maximum %zu bytes)", n_stat, max_length); + return _get_contents_error (error, EMSGSIZE, out_errsv, "file too large (%zu+1 bytes with maximum %zu bytes)", n_stat, max_length); str = g_try_malloc (n_stat + 1); if (!str) - return _get_contents_error (error, ENOMEM, "failure to allocate buffer of %zu+1 bytes", n_stat); + return _get_contents_error (error, ENOMEM, out_errsv, "failure to allocate buffer of %zu+1 bytes", n_stat); n_read = nm_utils_fd_read_loop (fd, str, n_stat, TRUE); if (n_read < 0) { if (do_bzero_mem) nm_explicit_bzero (str, n_stat); - return _get_contents_error (error, -n_read, "error reading %zu bytes from file descriptor", n_stat); + return _get_contents_error (error, -n_read, out_errsv, "error reading %zu bytes from file descriptor", n_stat); } str[n_read] = '\0'; if (n_read < n_stat) { if (!(str = _mem_realloc (str, do_bzero_mem, n_stat + 1, n_read + 1))) - return _get_contents_error (error, ENOMEM, "failure to reallocate buffer with %zu bytes", n_read + 1); + return _get_contents_error (error, ENOMEM, out_errsv, "failure to reallocate buffer with %zu bytes", n_read + 1); } NM_SET_OUT (length, n_read); } else { @@ -181,13 +176,13 @@ nm_utils_fd_get_contents (int fd, else { fd2 = fcntl (fd, F_DUPFD_CLOEXEC, 0); if (fd2 < 0) - return _get_contents_error_errno (error, "error during dup"); + return _get_contents_error_errno (error, out_errsv, "error during dup"); } if (!(f = fdopen (fd2, "r"))) { errsv = errno; nm_close (fd2); - return _get_contents_error (error, errsv, "failure during fdopen"); + return _get_contents_error (error, errsv, out_errsv, "failure during fdopen"); } n_have = 0; @@ -201,14 +196,14 @@ nm_utils_fd_get_contents (int fd, if (ferror (f)) { if (do_bzero_mem) nm_explicit_bzero (buf, sizeof (buf)); - return _get_contents_error (error, errsv, "error during fread"); + return _get_contents_error (error, errsv, out_errsv, "error during fread"); } if ( n_have > G_MAXSIZE - 1 - n_read || n_have + n_read + 1 > max_length) { if (do_bzero_mem) nm_explicit_bzero (buf, sizeof (buf)); - return _get_contents_error (error, EMSGSIZE, "file stream too large (%zu+1 bytes with maximum %zu bytes)", + return _get_contents_error (error, EMSGSIZE, out_errsv, "file stream too large (%zu+1 bytes with maximum %zu bytes)", (n_have > G_MAXSIZE - 1 - n_read) ? G_MAXSIZE : n_have + n_read, max_length); } @@ -230,7 +225,7 @@ nm_utils_fd_get_contents (int fd, if (!(str = _mem_realloc (str, do_bzero_mem, old_n_alloc, n_alloc))) { if (do_bzero_mem) nm_explicit_bzero (buf, sizeof (buf)); - return _get_contents_error (error, ENOMEM, "failure to allocate buffer of %zu bytes", n_alloc); + return _get_contents_error (error, ENOMEM, out_errsv, "failure to allocate buffer of %zu bytes", n_alloc); } } @@ -247,7 +242,7 @@ nm_utils_fd_get_contents (int fd, str[n_have] = '\0'; if (n_have + 1 < n_alloc) { if (!(str = _mem_realloc (str, do_bzero_mem, n_alloc, n_have + 1))) - return _get_contents_error (error, ENOMEM, "failure to truncate buffer to %zu bytes", n_have + 1); + return _get_contents_error (error, ENOMEM, out_errsv, "failure to truncate buffer to %zu bytes", n_have + 1); } } @@ -255,7 +250,8 @@ nm_utils_fd_get_contents (int fd, } *contents = g_steal_pointer (&str); - return 0; + NM_SET_OUT (out_errsv, 0); + return TRUE; } /** @@ -270,54 +266,49 @@ nm_utils_fd_get_contents (int fd, * the NUL byte. That is, it reads only files up to a length of * @max_length - 1 bytes. * @length: optional output argument of the read file size. + * @out_errsv: (allow-none) (out): on error, a positive errno. or zero. + * @error: * * A reimplementation of g_file_get_contents() with a few differences: * - accepts an @dirfd to open @filename relative to that path via openat(). * - limits the maximum filesize to max_length. * - uses O_CLOEXEC on internal file descriptor + * - optionally returns the native errno on failure. * - * Returns: a negative error code on failure. + * Returns: TRUE on success. */ -int +gboolean nm_utils_file_get_contents (int dirfd, const char *filename, gsize max_length, NMUtilsFileGetContentsFlags flags, char **contents, gsize *length, + int *out_errsv, GError **error) { int fd; - int errsv; - char bstrerr[NM_STRERROR_BUFSIZE]; - g_return_val_if_fail (filename && filename[0], -EINVAL); + g_return_val_if_fail (filename && filename[0], FALSE); + g_return_val_if_fail (contents && !*contents, FALSE); + + NM_SET_OUT (length, 0); if (dirfd >= 0) { fd = openat (dirfd, filename, O_RDONLY | O_CLOEXEC); if (fd < 0) { - errsv = errno; - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "Failed to open file \"%s\" with openat: %s", - filename, - nm_strerror_native_r (errsv, bstrerr, sizeof (bstrerr))); - return -NM_ERRNO_NATIVE (errsv); + return _get_contents_error_errno (error, + out_errsv, + "Failed to open file \"%s\" with openat", + filename); } } else { fd = open (filename, O_RDONLY | O_CLOEXEC); if (fd < 0) { - errsv = errno; - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "Failed to open file \"%s\": %s", - filename, - nm_strerror_native_r (errsv, bstrerr, sizeof (bstrerr))); - return -NM_ERRNO_NATIVE (errsv); + return _get_contents_error_errno (error, + out_errsv, + "Failed to open file \"%s\"", + filename); } } return nm_utils_fd_get_contents (fd, @@ -326,6 +317,7 @@ nm_utils_file_get_contents (int dirfd, flags, contents, length, + out_errsv, error); } @@ -340,6 +332,7 @@ nm_utils_file_set_contents (const char *filename, const char *contents, gssize length, mode_t mode, + int *out_errsv, GError **error) { gs_free char *tmp_name = NULL; @@ -347,7 +340,6 @@ nm_utils_file_set_contents (const char *filename, int errsv; gssize s; int fd; - char bstrerr[NM_STRERROR_BUFSIZE]; g_return_val_if_fail (filename, FALSE); g_return_val_if_fail (contents || !length, FALSE); @@ -360,33 +352,26 @@ nm_utils_file_set_contents (const char *filename, tmp_name = g_strdup_printf ("%s.XXXXXX", filename); fd = g_mkstemp_full (tmp_name, O_RDWR | O_CLOEXEC, mode); if (fd < 0) { - errsv = errno; - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "failed to create file %s: %s", - tmp_name, - nm_strerror_native_r (errsv, bstrerr, sizeof (bstrerr))); - return FALSE; + return _get_contents_error_errno (error, + out_errsv, + "failed to create file %s", + tmp_name); } while (length > 0) { s = write (fd, contents, length); if (s < 0) { - errsv = errno; + errsv = NM_ERRNO_NATIVE (errno); if (errsv == EINTR) continue; nm_close (fd); unlink (tmp_name); - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "failed to write to file %s: %s", - tmp_name, - nm_strerror_native_r (errsv, bstrerr, sizeof (bstrerr))); - return FALSE; + return _get_contents_error (error, + errsv, + out_errsv, + "failed to write to file %s", + tmp_name); } g_assert (s <= length); @@ -404,34 +389,28 @@ nm_utils_file_set_contents (const char *filename, if ( lstat (filename, &statbuf) == 0 && statbuf.st_size > 0) { if (fsync (fd) != 0) { - errsv = errno; - + errsv = NM_ERRNO_NATIVE (errno); nm_close (fd); unlink (tmp_name); - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "failed to fsync %s: %s", - tmp_name, - nm_strerror_native_r (errsv, bstrerr, sizeof (bstrerr))); - return FALSE; + return _get_contents_error (error, + errsv, + out_errsv, + "failed to fsync %s", + tmp_name); } } nm_close (fd); if (rename (tmp_name, filename)) { - errsv = errno; + errsv = NM_ERRNO_NATIVE (errno); unlink (tmp_name); - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "failed to rename %s to %s: %s", - tmp_name, - filename, - nm_strerror_native_r (errsv, bstrerr, sizeof (bstrerr))); - return FALSE; + return _get_contents_error (error, + errsv, + out_errsv, + "failed rename %s to %s", + tmp_name, + filename); } return TRUE; diff --git a/shared/nm-glib-aux/nm-io-utils.h b/shared/nm-glib-aux/nm-io-utils.h index 121fc481..18dc5f74 100644 --- a/shared/nm-glib-aux/nm-io-utils.h +++ b/shared/nm-glib-aux/nm-io-utils.h @@ -1,21 +1,6 @@ -/* 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 2018 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2018 Red Hat, Inc. */ #ifndef __NM_IO_UTILS_H__ @@ -37,26 +22,29 @@ typedef enum { NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET = (1 << 0), } NMUtilsFileGetContentsFlags; -int nm_utils_fd_get_contents (int fd, - gboolean close_fd, - gsize max_length, - NMUtilsFileGetContentsFlags flags, - char **contents, - gsize *length, - GError **error); - -int nm_utils_file_get_contents (int dirfd, - const char *filename, - gsize max_length, - NMUtilsFileGetContentsFlags flags, - char **contents, - gsize *length, - GError **error); +gboolean nm_utils_fd_get_contents (int fd, + gboolean close_fd, + gsize max_length, + NMUtilsFileGetContentsFlags flags, + char **contents, + gsize *length, + int *out_errsv, + GError **error); + +gboolean nm_utils_file_get_contents (int dirfd, + const char *filename, + gsize max_length, + NMUtilsFileGetContentsFlags flags, + char **contents, + gsize *length, + int *out_errsv, + GError **error); gboolean nm_utils_file_set_contents (const char *filename, const char *contents, gssize length, mode_t mode, + int *out_errsv, GError **error); struct stat; diff --git a/shared/nm-glib-aux/nm-jansson.h b/shared/nm-glib-aux/nm-jansson.h index d4642319..0a75cff5 100644 --- a/shared/nm-glib-aux/nm-jansson.h +++ b/shared/nm-glib-aux/nm-jansson.h @@ -1,19 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0+ /* - * 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 2018 Red Hat, Inc. + * Copyright (C) 2018 Red Hat, Inc. */ #ifndef __NM_JANSSON_H__ diff --git a/shared/nm-glib-aux/nm-json-aux.c b/shared/nm-glib-aux/nm-json-aux.c index 6f04ef2b..a738ab72 100644 --- a/shared/nm-glib-aux/nm-json-aux.c +++ b/shared/nm-glib-aux/nm-json-aux.c @@ -1,20 +1,6 @@ +// SPDX-License-Identifier: LGPL-2.1+ /* - * 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. - * - * Copyright 2019 Red Hat, Inc. + * Copyright (C) 2019 Red Hat, Inc. */ #include "nm-default.h" diff --git a/shared/nm-glib-aux/nm-json-aux.h b/shared/nm-glib-aux/nm-json-aux.h index 19d43ce4..ed3be376 100644 --- a/shared/nm-glib-aux/nm-json-aux.h +++ b/shared/nm-glib-aux/nm-json-aux.h @@ -1,20 +1,6 @@ +// SPDX-License-Identifier: LGPL-2.1+ /* - * 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. - * - * Copyright 2019 Red Hat, Inc. + * Copyright (C) 2019 Red Hat, Inc. */ #ifndef __NM_JSON_AUX_H__ diff --git a/shared/nm-glib-aux/nm-keyfile-aux.c b/shared/nm-glib-aux/nm-keyfile-aux.c index 989c773f..8b2af7a8 100644 --- a/shared/nm-glib-aux/nm-keyfile-aux.c +++ b/shared/nm-glib-aux/nm-keyfile-aux.c @@ -1,21 +1,6 @@ -/* 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 2019 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2019 Red Hat, Inc. */ #include "nm-default.h" @@ -186,7 +171,6 @@ nm_key_file_db_destroy (NMKeyFileDB *self) void nm_key_file_db_start (NMKeyFileDB *self) { - int r; gs_free char *contents = NULL; gsize contents_len; gs_free_error GError *error = NULL; @@ -196,14 +180,14 @@ nm_key_file_db_start (NMKeyFileDB *self) self->is_started = TRUE; - r = nm_utils_file_get_contents (-1, - self->filename, - 20*1024*1024, - NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, - &contents, - &contents_len, - &error); - if (r < 0) { + if (!nm_utils_file_get_contents (-1, + self->filename, + 20*1024*1024, + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, + &contents, + &contents_len, + NULL, + &error)) { _LOGD ("failed to read \"%s\": %s", self->filename, error->message); return; } diff --git a/shared/nm-glib-aux/nm-keyfile-aux.h b/shared/nm-glib-aux/nm-keyfile-aux.h index 8563f4d1..0f729c72 100644 --- a/shared/nm-glib-aux/nm-keyfile-aux.h +++ b/shared/nm-glib-aux/nm-keyfile-aux.h @@ -1,21 +1,6 @@ -/* 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 2019 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2019 Red Hat, Inc. */ #ifndef __NM_KEYFILE_AUX_H__ diff --git a/shared/nm-glib-aux/nm-logging-base.c b/shared/nm-glib-aux/nm-logging-base.c new file mode 100644 index 00000000..47b3e993 --- /dev/null +++ b/shared/nm-glib-aux/nm-logging-base.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#include "nm-default.h" + +#include "nm-logging-base.h" + +#include <syslog.h> + +/*****************************************************************************/ + +const LogLevelDesc level_desc[_LOGL_N] = { + [LOGL_TRACE] = { "TRACE", "<trace>", LOG_DEBUG, G_LOG_LEVEL_DEBUG, }, + [LOGL_DEBUG] = { "DEBUG", "<debug>", LOG_DEBUG, G_LOG_LEVEL_DEBUG, }, + [LOGL_INFO] = { "INFO", "<info>", LOG_INFO, G_LOG_LEVEL_INFO, }, + [LOGL_WARN] = { "WARN", "<warn>", LOG_WARNING, G_LOG_LEVEL_MESSAGE, }, + [LOGL_ERR] = { "ERR", "<error>", LOG_ERR, G_LOG_LEVEL_MESSAGE, }, + [_LOGL_OFF] = { "OFF", NULL, 0, 0, }, + [_LOGL_KEEP] = { "KEEP", NULL, 0, 0, }, +}; + +gboolean +_nm_log_parse_level (const char *level, + NMLogLevel *out_level) +{ + int i; + + if (!level) + return FALSE; + + for (i = 0; i < (int) G_N_ELEMENTS (level_desc); i++) { + if (!g_ascii_strcasecmp (level_desc[i].name, level)) { + NM_SET_OUT (out_level, i); + return TRUE; + } + } + + return FALSE; +} diff --git a/shared/nm-glib-aux/nm-logging-base.h b/shared/nm-glib-aux/nm-logging-base.h new file mode 100644 index 00000000..3d964a6e --- /dev/null +++ b/shared/nm-glib-aux/nm-logging-base.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#ifndef __NM_LOGGING_BASE_H__ +#define __NM_LOGGING_BASE_H__ + +#include "nm-logging-fwd.h" + +typedef struct { + const char *name; + const char *level_str; + + /* nm-logging uses syslog internally. Note that the three most-verbose syslog levels + * are LOG_DEBUG, LOG_INFO and LOG_NOTICE. Journal already highlights LOG_NOTICE + * as special. + * + * On the other hand, we have three levels LOGL_TRACE, LOGL_DEBUG and LOGL_INFO, + * which are regular messages not to be highlighted. For that reason, we must map + * LOGL_TRACE and LOGL_DEBUG both to syslog level LOG_DEBUG. */ + int syslog_level; + + GLogLevelFlags g_log_level; +} LogLevelDesc; + +extern const LogLevelDesc level_desc[_LOGL_N]; + +gboolean _nm_log_parse_level (const char *level, + NMLogLevel *out_level); + +#endif /* __NM_LOGGING_BASE_H__ */ diff --git a/shared/nm-glib-aux/nm-logging-fwd.h b/shared/nm-glib-aux/nm-logging-fwd.h index c60a20b5..47661788 100644 --- a/shared/nm-glib-aux/nm-logging-fwd.h +++ b/shared/nm-glib-aux/nm-logging-fwd.h @@ -1,26 +1,11 @@ -/* 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. - * +// SPDX-License-Identifier: LGPL-2.1+ +/* * Copyright (C) 2006 - 2018 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ -#ifndef __NM_LOGGING_DEFINES_H__ -#define __NM_LOGGING_DEFINES_H__ +#ifndef __NM_LOGGING_FWD_H__ +#define __NM_LOGGING_FWD_H__ /* Log domains */ @@ -127,6 +112,19 @@ nm_log_level_from_syslog (int syslog_level) } } +static inline int +nm_log_level_to_syslog (NMLogLevel nm_level) +{ + switch (nm_level) { + case LOGL_ERR: return 3; /* LOG_ERR */ + case LOGL_WARN: return 4; /* LOG_WARN */ + case LOGL_INFO: return 5; /* LOG_NOTICE */ + case LOGL_DEBUG: return 6; /* LOG_INFO */ + case LOGL_TRACE: return 7; /* LOG_DEBUG */ + default: return 0; /* LOG_EMERG */ + } +} + /*****************************************************************************/ struct timespec; @@ -137,4 +135,120 @@ extern void _nm_utils_monotonic_timestamp_initialized (const struct timespec *tp gint64 offset_sec, gboolean is_boottime); -#endif /* __NM_LOGGING_DEFINES_H__ */ +/*****************************************************************************/ + +#define _LOGL_TRACE LOGL_TRACE +#define _LOGL_DEBUG LOGL_DEBUG +#define _LOGL_INFO LOGL_INFO +#define _LOGL_WARN LOGL_WARN +#define _LOGL_ERR LOGL_ERR + +/* This is the default definition of _NMLOG_ENABLED(). Special implementations + * might want to undef this and redefine it. */ +#define _NMLOG_ENABLED(level) ( nm_logging_enabled ((level), (_NMLOG_DOMAIN)) ) + +#define _LOGT(...) _NMLOG (_LOGL_TRACE, __VA_ARGS__) +#define _LOGD(...) _NMLOG (_LOGL_DEBUG, __VA_ARGS__) +#define _LOGI(...) _NMLOG (_LOGL_INFO , __VA_ARGS__) +#define _LOGW(...) _NMLOG (_LOGL_WARN , __VA_ARGS__) +#define _LOGE(...) _NMLOG (_LOGL_ERR , __VA_ARGS__) + +#define _LOGT_ENABLED(...) _NMLOG_ENABLED (_LOGL_TRACE, ##__VA_ARGS__) +#define _LOGD_ENABLED(...) _NMLOG_ENABLED (_LOGL_DEBUG, ##__VA_ARGS__) +#define _LOGI_ENABLED(...) _NMLOG_ENABLED (_LOGL_INFO , ##__VA_ARGS__) +#define _LOGW_ENABLED(...) _NMLOG_ENABLED (_LOGL_WARN , ##__VA_ARGS__) +#define _LOGE_ENABLED(...) _NMLOG_ENABLED (_LOGL_ERR , ##__VA_ARGS__) + +#define _LOGT_err(errsv, ...) _NMLOG_err (errsv, _LOGL_TRACE, __VA_ARGS__) +#define _LOGD_err(errsv, ...) _NMLOG_err (errsv, _LOGL_DEBUG, __VA_ARGS__) +#define _LOGI_err(errsv, ...) _NMLOG_err (errsv, _LOGL_INFO , __VA_ARGS__) +#define _LOGW_err(errsv, ...) _NMLOG_err (errsv, _LOGL_WARN , __VA_ARGS__) +#define _LOGE_err(errsv, ...) _NMLOG_err (errsv, _LOGL_ERR , __VA_ARGS__) + +/* _LOGT() and _LOGt() both log with level TRACE, but the latter is disabled by default, + * unless building with --with-more-logging. */ +#if NM_MORE_LOGGING +#define _LOGt_ENABLED(...) _NMLOG_ENABLED (_LOGL_TRACE, ##__VA_ARGS__) +#define _LOGt(...) _NMLOG (_LOGL_TRACE, __VA_ARGS__) +#define _LOGt_err(errsv, ...) _NMLOG_err (errsv, _LOGL_TRACE, __VA_ARGS__) +#else +/* still call the logging macros to get compile time checks, but they will be optimized out. */ +#define _LOGt_ENABLED(...) ( FALSE && (_NMLOG_ENABLED (_LOGL_TRACE, ##__VA_ARGS__)) ) +#define _LOGt(...) G_STMT_START { if (FALSE) { _NMLOG (_LOGL_TRACE, __VA_ARGS__); } } G_STMT_END +#define _LOGt_err(errsv, ...) G_STMT_START { if (FALSE) { _NMLOG_err (errsv, _LOGL_TRACE, __VA_ARGS__); } } G_STMT_END +#endif + +/*****************************************************************************/ + +/* Some implementation define a second set of logging macros, for a separate + * use. As with the _LOGD() macro family above, the exact implementation + * depends on the file that uses them. + * Still, it encourages a common pattern to have the common set of macros + * like _LOG2D(), _LOG2I(), etc. and have _LOG2t() which by default + * is disabled at compile time. */ + +#define _NMLOG2_ENABLED(level) ( nm_logging_enabled ((level), (_NMLOG2_DOMAIN)) ) + +#define _LOG2T(...) _NMLOG2 (_LOGL_TRACE, __VA_ARGS__) +#define _LOG2D(...) _NMLOG2 (_LOGL_DEBUG, __VA_ARGS__) +#define _LOG2I(...) _NMLOG2 (_LOGL_INFO , __VA_ARGS__) +#define _LOG2W(...) _NMLOG2 (_LOGL_WARN , __VA_ARGS__) +#define _LOG2E(...) _NMLOG2 (_LOGL_ERR , __VA_ARGS__) + +#define _LOG2T_ENABLED(...) _NMLOG2_ENABLED (_LOGL_TRACE, ##__VA_ARGS__) +#define _LOG2D_ENABLED(...) _NMLOG2_ENABLED (_LOGL_DEBUG, ##__VA_ARGS__) +#define _LOG2I_ENABLED(...) _NMLOG2_ENABLED (_LOGL_INFO , ##__VA_ARGS__) +#define _LOG2W_ENABLED(...) _NMLOG2_ENABLED (_LOGL_WARN , ##__VA_ARGS__) +#define _LOG2E_ENABLED(...) _NMLOG2_ENABLED (_LOGL_ERR , ##__VA_ARGS__) + +#define _LOG2T_err(errsv, ...) _NMLOG2_err (errsv, _LOGL_TRACE, __VA_ARGS__) +#define _LOG2D_err(errsv, ...) _NMLOG2_err (errsv, _LOGL_DEBUG, __VA_ARGS__) +#define _LOG2I_err(errsv, ...) _NMLOG2_err (errsv, _LOGL_INFO , __VA_ARGS__) +#define _LOG2W_err(errsv, ...) _NMLOG2_err (errsv, _LOGL_WARN , __VA_ARGS__) +#define _LOG2E_err(errsv, ...) _NMLOG2_err (errsv, _LOGL_ERR , __VA_ARGS__) + +#if NM_MORE_LOGGING +#define _LOG2t_ENABLED(...) _NMLOG2_ENABLED (_LOGL_TRACE, ##__VA_ARGS__) +#define _LOG2t(...) _NMLOG2 (_LOGL_TRACE, __VA_ARGS__) +#define _LOG2t_err(errsv, ...) _NMLOG2_err (errsv, _LOGL_TRACE, __VA_ARGS__) +#else +/* still call the logging macros to get compile time checks, but they will be optimized out. */ +#define _LOG2t_ENABLED(...) ( FALSE && (_NMLOG2_ENABLED (_LOGL_TRACE, ##__VA_ARGS__)) ) +#define _LOG2t(...) G_STMT_START { if (FALSE) { _NMLOG2 (_LOGL_TRACE, __VA_ARGS__); } } G_STMT_END +#define _LOG2t_err(errsv, ...) G_STMT_START { if (FALSE) { _NMLOG2_err (errsv, _LOGL_TRACE, __VA_ARGS__); } } G_STMT_END +#endif + +#define _NMLOG3_ENABLED(level) ( nm_logging_enabled ((level), (_NMLOG3_DOMAIN)) ) + +#define _LOG3T(...) _NMLOG3 (_LOGL_TRACE, __VA_ARGS__) +#define _LOG3D(...) _NMLOG3 (_LOGL_DEBUG, __VA_ARGS__) +#define _LOG3I(...) _NMLOG3 (_LOGL_INFO , __VA_ARGS__) +#define _LOG3W(...) _NMLOG3 (_LOGL_WARN , __VA_ARGS__) +#define _LOG3E(...) _NMLOG3 (_LOGL_ERR , __VA_ARGS__) + +#define _LOG3T_ENABLED(...) _NMLOG3_ENABLED (_LOGL_TRACE, ##__VA_ARGS__) +#define _LOG3D_ENABLED(...) _NMLOG3_ENABLED (_LOGL_DEBUG, ##__VA_ARGS__) +#define _LOG3I_ENABLED(...) _NMLOG3_ENABLED (_LOGL_INFO , ##__VA_ARGS__) +#define _LOG3W_ENABLED(...) _NMLOG3_ENABLED (_LOGL_WARN , ##__VA_ARGS__) +#define _LOG3E_ENABLED(...) _NMLOG3_ENABLED (_LOGL_ERR , ##__VA_ARGS__) + +#define _LOG3T_err(errsv, ...) _NMLOG3_err (errsv, _LOGL_TRACE, __VA_ARGS__) +#define _LOG3D_err(errsv, ...) _NMLOG3_err (errsv, _LOGL_DEBUG, __VA_ARGS__) +#define _LOG3I_err(errsv, ...) _NMLOG3_err (errsv, _LOGL_INFO , __VA_ARGS__) +#define _LOG3W_err(errsv, ...) _NMLOG3_err (errsv, _LOGL_WARN , __VA_ARGS__) +#define _LOG3E_err(errsv, ...) _NMLOG3_err (errsv, _LOGL_ERR , __VA_ARGS__) + +#if NM_MORE_LOGGING +#define _LOG3t_ENABLED(...) _NMLOG3_ENABLED (_LOGL_TRACE, ##__VA_ARGS__) +#define _LOG3t(...) _NMLOG3 (_LOGL_TRACE, __VA_ARGS__) +#define _LOG3t_err(errsv, ...) _NMLOG3_err (errsv, _LOGL_TRACE, __VA_ARGS__) +#else +/* still call the logging macros to get compile time checks, but they will be optimized out. */ +#define _LOG3t_ENABLED(...) ( FALSE && (_NMLOG3_ENABLED (_LOGL_TRACE, ##__VA_ARGS__)) ) +#define _LOG3t(...) G_STMT_START { if (FALSE) { _NMLOG3 (_LOGL_TRACE, __VA_ARGS__); } } G_STMT_END +#define _LOG3t_err(errsv, ...) G_STMT_START { if (FALSE) { _NMLOG3_err (errsv, _LOGL_TRACE, __VA_ARGS__); } } G_STMT_END +#endif + +/*****************************************************************************/ + +#endif /* __NM_LOGGING_FWD_H__ */ diff --git a/shared/nm-glib-aux/nm-macros-internal.h b/shared/nm-glib-aux/nm-macros-internal.h index 9502c442..d1ea04c0 100644 --- a/shared/nm-glib-aux/nm-macros-internal.h +++ b/shared/nm-glib-aux/nm-macros-internal.h @@ -1,22 +1,7 @@ -/* 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 2012 Colin Walters <walters@verbum.org>. - * (C) Copyright 2014 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2012 Colin Walters <walters@verbum.org>. + * Copyright (C) 2014 Red Hat, Inc. */ #ifndef __NM_MACROS_INTERNAL_H__ @@ -324,6 +309,12 @@ _nm_auto_protect_errno (int *p_saved_errno) NM_AUTO_DEFINE_FCN0 (GSource *, _nm_auto_unref_gsource, g_source_unref); #define nm_auto_unref_gsource nm_auto(_nm_auto_unref_gsource) +NM_AUTO_DEFINE_FCN0 (guint, _nm_auto_remove_source, g_source_remove); +#define nm_auto_remove_source nm_auto(_nm_auto_remove_source) + +NM_AUTO_DEFINE_FCN0 (GIOChannel *, _nm_auto_unref_io_channel, g_io_channel_unref) +#define nm_auto_unref_io_channel nm_auto(_nm_auto_unref_io_channel) + NM_AUTO_DEFINE_FCN0 (GMainLoop *, _nm_auto_unref_gmainloop, g_main_loop_unref); #define nm_auto_unref_gmainloop nm_auto(_nm_auto_unref_gmainloop) @@ -644,6 +635,13 @@ NM_G_ERROR_MSG (GError *error) #define _NM_ENSURE_TYPE_CONST(type, value) ((const type) (value)) #endif +#if _NM_CC_SUPPORT_GENERIC && ( !defined (__clang__) || __clang_major__ > 3 ) +#define NM_STRUCT_OFFSET_ENSURE_TYPE(type, container, field) (_Generic ( (&(((container *) NULL)->field))[0] , \ + type: G_STRUCT_OFFSET (container, field))) +#else +#define NM_STRUCT_OFFSET_ENSURE_TYPE(type, container, field) G_STRUCT_OFFSET (container, field) +#endif + #if _NM_CC_SUPPORT_GENERIC /* these macros cast (value) to * - "const char **" (for "MC", mutable-const) @@ -1045,7 +1043,7 @@ _nm_gobject_notify_together_impl (obj_type *obj, guint n, const property_enums_t g_object_thaw_notify ((GObject *) obj); \ } \ \ -static inline void \ +_nm_unused static inline void \ _notify (obj_type *obj, property_enums_type prop) \ { \ _nm_gobject_notify_together_impl (obj, 1, &prop); \ @@ -1270,6 +1268,25 @@ nm_clear_g_cancellable_disconnect (GCancellable *cancellable, gulong *cancellabl /*****************************************************************************/ +static inline const char * +nm_dbus_path_not_empty (const char *str) +{ + nm_assert (!str || str[0] == '/'); + return !str || (str[0] == '/' && str[1] == '\0') + ? NULL + : str; +} + +/*****************************************************************************/ + +/* GVariantType is basically a C string. But G_VARIANT_TYPE() is not suitable + * to initialize a static variable (because it evaluates a function check that + * the string is valid). Add an alternative macro that does the plain cast. + * + * Here you loose the assertion check that G_VARIANT_TYPE() to ensure the + * string is valid. */ +#define NM_G_VARIANT_TYPE(fmt) ((const GVariantType *) (""fmt"")) + static inline GVariant * nm_g_variant_ref (GVariant *v) { @@ -1989,4 +2006,18 @@ nm_close (int fd) #define NM_PID_T_INVAL ((pid_t) -1) +/*****************************************************************************/ + +NM_AUTO_DEFINE_FCN_VOID0 (GMutex *, _nm_auto_unlock_g_mutex, g_mutex_unlock) + +#define nm_auto_unlock_g_mutex nm_auto (_nm_auto_unlock_g_mutex) + +#define _NM_G_MUTEX_LOCKED(lock, uniq) \ + nm_auto_unlock_g_mutex GMutex *NM_UNIQ_T(nm_lock, uniq) = (lock) + +#define NM_G_MUTEX_LOCKED(lock) \ + _NM_G_MUTEX_LOCKED (lock, NM_UNIQ) + +/*****************************************************************************/ + #endif /* __NM_MACROS_INTERNAL_H__ */ diff --git a/shared/nm-glib-aux/nm-obj.h b/shared/nm-glib-aux/nm-obj.h index 06016bdd..cbfdba63 100644 --- a/shared/nm-glib-aux/nm-obj.h +++ b/shared/nm-glib-aux/nm-obj.h @@ -1,21 +1,6 @@ -/* 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. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2017 Red Hat, Inc. */ #ifndef __NM_OBJ_H__ diff --git a/shared/nm-glib-aux/nm-random-utils.c b/shared/nm-glib-aux/nm-random-utils.c index f56f8b99..95063c94 100644 --- a/shared/nm-glib-aux/nm-random-utils.c +++ b/shared/nm-glib-aux/nm-random-utils.c @@ -1,21 +1,6 @@ -/* 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. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2017 Red Hat, Inc. */ #include "nm-default.h" diff --git a/shared/nm-glib-aux/nm-random-utils.h b/shared/nm-glib-aux/nm-random-utils.h index 8e134ee9..056af38a 100644 --- a/shared/nm-glib-aux/nm-random-utils.h +++ b/shared/nm-glib-aux/nm-random-utils.h @@ -1,21 +1,6 @@ -/* 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. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2017 Red Hat, Inc. */ #ifndef __NM_RANDOM_UTILS_H__ diff --git a/shared/nm-glib-aux/nm-ref-string.c b/shared/nm-glib-aux/nm-ref-string.c new file mode 100644 index 00000000..0a0b0d3a --- /dev/null +++ b/shared/nm-glib-aux/nm-ref-string.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#include "nm-default.h" + +#include "nm-ref-string.h" + +/*****************************************************************************/ + +typedef struct { + NMRefString r; + volatile int ref_count; + char str_data[]; +} RefString; + +G_LOCK_DEFINE_STATIC (gl_lock); +static GHashTable *gl_hash; + +/* the first field of NMRefString is a pointer to the NUL terminated string. + * This also allows to compare strings with nm_pstr_equal(), although, pointer + * equality might be better. */ +G_STATIC_ASSERT (G_STRUCT_OFFSET (NMRefString, str) == 0); +G_STATIC_ASSERT (G_STRUCT_OFFSET (RefString, r) == 0); +G_STATIC_ASSERT (G_STRUCT_OFFSET (RefString, r.str) == 0); + +/*****************************************************************************/ + +static guint +_ref_string_hash (gconstpointer ptr) +{ + const RefString *a = ptr; + NMHashState h; + + nm_hash_init (&h, 1463435489u); + nm_hash_update (&h, a->r.str, a->r.len); + return nm_hash_complete (&h); +} + +static gboolean +_ref_string_equal (gconstpointer pa, gconstpointer pb) +{ + const RefString *a = pa; + const RefString *b = pb; + + return a->r.len == b->r.len + && memcmp (a->r.str, b->r.str, a->r.len) == 0; +} + +/*****************************************************************************/ + +static void +_ASSERT (const RefString *rstr0) +{ +#if NM_MORE_ASSERTS + int r; + + nm_assert (rstr0); + + G_LOCK (gl_lock); + r = g_atomic_int_get (&rstr0->ref_count); + + nm_assert (r > 0); + nm_assert (r < G_MAXINT); + + nm_assert (rstr0 == g_hash_table_lookup (gl_hash, rstr0)); + G_UNLOCK (gl_lock); +#endif +} + +/** + * nm_ref_string_new_len: + * @cstr: the string to intern. Must contain @len bytes. + * If @len is zero, @cstr may be %NULL. Note that it is + * accetable that the string contains a NUL character + * within the first @len bytes. That is, the string is + * not treated as a NUL terminated string, but as binary. + * Also, contrary to strncpy(), this will read all the + * first @len bytes. It won't stop at the first NUL. + * @len: the length of the string (usually there is no NUL character + * within the first @len bytes, but that would be acceptable as well + * to add binary data). + * + * Note that the resulting NMRefString instance will always be NUL terminated + * (at position @len). + * + * Note that NMRefString are always interned/deduplicated. If such a string + * already exists, the existing instance will be refered and returned. + * + * + * Since all NMRefString are shared and interned, you may use + * pointer equality to compare them. Note that if a NMRefString contains + * a NUL character (meaning, if + * + * strlen (nm_ref_string_get_str (str)) != nm_ref_string_get_len (str) + * + * ), then pointer in-equality does not mean that the NUL terminated strings + * are also unequal. In other words, for strings that contain NUL characters, + * + * if (str1 != str2) + * assert (!nm_streq0 (nm_ref_string_get_str (str1), nm_ref_string_get_str (str2))); + * + * might not hold! + * + * + * NMRefString is thread-safe. + * + * Returns: (transfer full): the interned string. This is + * never %NULL, but note that %NULL is also a valid NMRefString. + * The result must be unrefed with nm_ref_string_unref(). + */ +NMRefString * +nm_ref_string_new_len (const char *cstr, gsize len) +{ + RefString *rstr0; + + G_LOCK (gl_lock); + + if (G_UNLIKELY (!gl_hash)) { + gl_hash = g_hash_table_new_full (_ref_string_hash, _ref_string_equal, g_free, NULL); + rstr0 = NULL; + } else { + NMRefString rr_lookup = { + .len = len, + .str = cstr, + }; + + rstr0 = g_hash_table_lookup (gl_hash, &rr_lookup); + } + + if (rstr0) { + nm_assert (({ + int r = g_atomic_int_get (&rstr0->ref_count); + + (r >= 0 && r < G_MAXINT); + })); + g_atomic_int_inc (&rstr0->ref_count); + } else { + rstr0 = g_malloc (sizeof (RefString) + 1 + len); + rstr0->ref_count = 1; + *((gsize *) &rstr0->r.len) = len; + *((const char **) &rstr0->r.str) = rstr0->str_data; + if (len > 0) + memcpy (rstr0->str_data, cstr, len); + rstr0->str_data[len] = '\0'; + + if (!g_hash_table_add (gl_hash, rstr0)) + nm_assert_not_reached (); + } + + G_UNLOCK (gl_lock); + + return &rstr0->r; +} + +NMRefString * +nm_ref_string_ref (NMRefString *rstr) +{ + RefString *const rstr0 = (RefString *) rstr; + + if (!rstr) + return NULL; + + _ASSERT (rstr0); + + g_atomic_int_inc (&rstr0->ref_count); + return &rstr0->r; +} + +void +_nm_ref_string_unref_non_null (NMRefString *rstr) +{ + RefString *const rstr0 = (RefString *) rstr; + + _ASSERT (rstr0); + + if (G_LIKELY (!g_atomic_int_dec_and_test (&rstr0->ref_count))) + return; + + G_LOCK (gl_lock); + + /* in the fast-path above, we already decremented the ref-count to zero. + * We need recheck that the ref-count is still zero. */ + + if (g_atomic_int_get (&rstr0->ref_count) == 0) { + if (!g_hash_table_remove (gl_hash, rstr0)) + nm_assert_not_reached (); + } else { +#if NM_MORE_ASSERTS > 5 + nm_assert (g_hash_table_lookup (gl_hash, rstr0) == rstr0); +#endif + } + + G_UNLOCK (gl_lock); +} + +/*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-ref-string.h b/shared/nm-glib-aux/nm-ref-string.h new file mode 100644 index 00000000..c80b75ea --- /dev/null +++ b/shared/nm-glib-aux/nm-ref-string.h @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#ifndef __NM_REF_STRING_H__ +#define __NM_REF_STRING_H__ + +/*****************************************************************************/ + +typedef struct _NMRefString { + const char *const str; + const gsize len; +} NMRefString; + +/*****************************************************************************/ + +NMRefString *nm_ref_string_new_len (const char *cstr, gsize len); + +static inline NMRefString * +nm_ref_string_new (const char *cstr) +{ + return cstr + ? nm_ref_string_new_len (cstr, strlen (cstr)) + : NULL; +} + +NMRefString *nm_ref_string_ref (NMRefString *rstr); +void _nm_ref_string_unref_non_null (NMRefString *rstr); + +static inline void +nm_ref_string_unref (NMRefString *rstr) +{ + if (rstr) + _nm_ref_string_unref_non_null (rstr); +} + +NM_AUTO_DEFINE_FCN_VOID0 (NMRefString *, _nm_auto_ref_string, _nm_ref_string_unref_non_null) +#define nm_auto_ref_string nm_auto(_nm_auto_ref_string) + +/*****************************************************************************/ + +static inline const char * +nm_ref_string_get_str (NMRefString *rstr) +{ + return rstr ? rstr->str : NULL; +} + +static inline gsize +nm_ref_string_get_len (NMRefString *rstr) +{ + return rstr ? rstr->len : 0u; +} + +static inline gboolean +NM_IS_REF_STRING (const NMRefString *rstr) +{ +#if NM_MORE_ASSERTS > 10 + if (rstr) { + nm_auto_ref_string NMRefString *r2 = NULL; + + r2 = nm_ref_string_new_len (rstr->str, rstr->len); + nm_assert (rstr == r2); + } +#endif + + /* Technically, %NULL is also a valid NMRefString (according to nm_ref_string_new(), + * nm_ref_string_get_str() and nm_ref_string_unref()). However, NM_IS_REF_STRING() + * does not think so. If callers want to allow %NULL, they need to check + * separately. */ + return !!rstr; +} + +#endif /* __NM_REF_STRING_H__ */ diff --git a/shared/nm-glib-aux/nm-secret-utils.c b/shared/nm-glib-aux/nm-secret-utils.c index aeb88877..5b0afe46 100644 --- a/shared/nm-glib-aux/nm-secret-utils.c +++ b/shared/nm-glib-aux/nm-secret-utils.c @@ -1,22 +1,7 @@ -/* 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 2018 Red Hat, Inc. - * (C) Copyright 2015 - 2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2018 Red Hat, Inc. + * Copyright (C) 2015 - 2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */ #include "nm-default.h" diff --git a/shared/nm-glib-aux/nm-secret-utils.h b/shared/nm-glib-aux/nm-secret-utils.h index 0fd1ac8b..1b98b7e9 100644 --- a/shared/nm-glib-aux/nm-secret-utils.h +++ b/shared/nm-glib-aux/nm-secret-utils.h @@ -1,21 +1,6 @@ -/* 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 2018 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2018 Red Hat, Inc. */ #ifndef __NM_SECRET_UTILS_H__ diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 9bfd5ae2..8e1c8b58 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -1,21 +1,6 @@ -/* 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 2016 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2016 Red Hat, Inc. */ #include "nm-default.h" @@ -26,6 +11,7 @@ #include <poll.h> #include <fcntl.h> #include <sys/syscall.h> +#include <glib-unix.h> #include "nm-errno.h" @@ -555,6 +541,102 @@ _nm_utils_ip4_prefix_to_netmask (guint32 prefix) return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF; } +gconstpointer +nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer src, guint8 plen) +{ + g_return_val_if_fail (dst, NULL); + + switch (family) { + case AF_INET: + g_return_val_if_fail (plen <= 32, NULL); + + if (!src) { + /* allow "self-assignment", by specifying %NULL as source. */ + src = dst; + } + + *((guint32 *) dst) = nm_utils_ip4_address_clear_host_address (*((guint32 *) src), plen); + break; + case AF_INET6: + nm_utils_ip6_address_clear_host_address (dst, src, plen); + break; + default: + g_return_val_if_reached (NULL); + } + return dst; +} + +/* nm_utils_ip4_address_clear_host_address: + * @addr: source ip6 address + * @plen: prefix length of network + * + * returns: the input address, with the host address set to 0. + */ +in_addr_t +nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen) +{ + return addr & _nm_utils_ip4_prefix_to_netmask (plen); +} + +/* nm_utils_ip6_address_clear_host_address: + * @dst: destination output buffer, will contain the network part of the @src address + * @src: source ip6 address + * @plen: prefix length of network + * + * Note: this function is self assignment safe, to update @src inplace, set both + * @dst and @src to the same destination or set @src NULL. + */ +const struct in6_addr * +nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen) +{ + g_return_val_if_fail (plen <= 128, NULL); + g_return_val_if_fail (dst, NULL); + + if (!src) + src = dst; + + if (plen < 128) { + guint nbytes = plen / 8; + guint nbits = plen % 8; + + if (nbytes && dst != src) + memcpy (dst, src, nbytes); + if (nbits) { + dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits))); + nbytes++; + } + if (nbytes <= 15) + memset (&dst->s6_addr[nbytes], 0, 16 - nbytes); + } else if (src != dst) + *dst = *src; + + return dst; +} + +int +nm_utils_ip6_address_same_prefix_cmp (const struct in6_addr *addr_a, const struct in6_addr *addr_b, guint8 plen) +{ + int nbytes; + guint8 va, vb, m; + + if (plen >= 128) + NM_CMP_DIRECT_MEMCMP (addr_a, addr_b, sizeof (struct in6_addr)); + else { + nbytes = plen / 8; + if (nbytes) + NM_CMP_DIRECT_MEMCMP (addr_a, addr_b, nbytes); + + plen = plen % 8; + if (plen != 0) { + m = ~((1 << (8 - plen)) - 1); + va = ((((const guint8 *) addr_a))[nbytes]) & m; + vb = ((((const guint8 *) addr_b))[nbytes]) & m; + NM_CMP_DIRECT (va, vb); + } + } + return 0; +} + /** * _nm_utils_ip4_get_default_prefix: * @ip: an IPv4 address (in network byte order) @@ -601,11 +683,80 @@ nm_utils_ip_is_site_local (int addr_family, /*****************************************************************************/ +static gboolean +_parse_legacy_addr4 (const char *text, in_addr_t *out_addr) +{ + gs_free char *s_free = NULL; + struct in_addr a1; + guint8 bin[sizeof (a1)]; + char *s; + int i; + + if (inet_aton (text, &a1) != 1) + return FALSE; + + /* OK, inet_aton() accepted the format. That's good, because we want + * to accept IPv4 addresses in octal format, like 255.255.000.000. + * That's what "legacy" means here. inet_pton() doesn't accept those. + * + * But inet_aton() also ignores trailing garbage and formats with fewer than + * 4 digits. That is just too crazy and we don't do that. Perform additional checks + * and reject some forms that inet_aton() accepted. + * + * Note that we still should (of course) accept everything that inet_pton() + * accepts. However this code never gets called if inet_pton() succeeds + * (see below, aside the assertion code). */ + + if (NM_STRCHAR_ANY (text, ch, ( !(ch >= '0' && ch <= '9') + && !NM_IN_SET (ch, '.', 'x')))) { + /* We only accepts '.', digits, and 'x' for "0x". */ + return FALSE; + } + + s = nm_memdup_maybe_a (300, text, strlen (text) + 1, &s_free); + + for (i = 0; i < G_N_ELEMENTS (bin); i++) { + char *current_token = s; + gint32 v; + + s = strchr (s, '.'); + if (s) { + s[0] = '\0'; + s++; + } + + if ((i == G_N_ELEMENTS (bin) - 1) != (s == NULL)) { + /* Exactly for the last digit, we expect to have no more following token. + * But this isn't the case. Abort. */ + return FALSE; + } + + v = _nm_utils_ascii_str_to_int64 (current_token, 0, 0, 0xFF, -1); + if (v == -1) { + /* we do accept octal and hex (even with leading "0x"). But something + * about this token is wrong. */ + return FALSE; + } + + bin[i] = v; + } + + if (memcmp (bin, &a1, sizeof (bin)) != 0) { + /* our parsing did not agree with what inet_aton() gave. Something + * is wrong. Abort. */ + return FALSE; + } + + *out_addr = a1.s_addr; + return TRUE; +} + gboolean -nm_utils_parse_inaddr_bin (int addr_family, - const char *text, - int *out_addr_family, - gpointer out_addr) +nm_utils_parse_inaddr_bin_full (int addr_family, + gboolean accept_legacy, + const char *text, + int *out_addr_family, + gpointer out_addr) { NMIPAddr addrbin; @@ -617,8 +768,26 @@ nm_utils_parse_inaddr_bin (int addr_family, } else g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), FALSE); - if (inet_pton (addr_family, text, &addrbin) != 1) - return FALSE; + if (inet_pton (addr_family, text, &addrbin) != 1) { + if ( accept_legacy + && addr_family == AF_INET + && _parse_legacy_addr4 (text, &addrbin.addr4)) { + /* The address is in some legacy format which inet_aton() accepts, but not inet_pton(). + * Most likely octal digits (leading zeros). We accept the address. */ + } else + return FALSE; + } + +#if NM_MORE_ASSERTS > 10 + if (addr_family == AF_INET) { + in_addr_t a; + + /* The legacy parser should accept everything that inet_pton() accepts too. Meaning, + * it should strictly parse *more* formats. And of course, parse it the same way. */ + nm_assert (_parse_legacy_addr4 (text, &a)); + nm_assert (addrbin.addr4 == a); + } +#endif NM_SET_OUT (out_addr_family, addr_family); if (out_addr) @@ -2302,6 +2471,44 @@ nm_utils_hash_keys_to_array (GHashTable *hash, return keys; } +gpointer * +nm_utils_hash_values_to_array (GHashTable *hash, + GCompareDataFunc compare_func, + gpointer user_data, + guint *out_len) +{ + GHashTableIter iter; + gpointer value; + gpointer *arr; + guint i, len; + + if ( !hash + || (len = g_hash_table_size (hash)) == 0u) { + NM_SET_OUT (out_len, 0); + return NULL; + } + + arr = g_new (gpointer, ((gsize) len) + 1); + i = 0; + g_hash_table_iter_init (&iter, hash); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &value)) + arr[i++] = value; + + nm_assert (i == len); + arr[len] = NULL; + + if ( len > 1 + && compare_func) { + g_qsort_with_data (arr, + len, + sizeof (gpointer), + compare_func, + user_data); + } + + return arr; +} + gboolean nm_utils_hashtable_same_keys (const GHashTable *a, const GHashTable *b) @@ -2370,6 +2577,10 @@ nm_utils_strv_make_deep_copied_n (const char **strv, gsize len) * is negative or zero (in which case %NULL will be returned). * @len: the length of strings in @str. If negative, strv is assumed * to be a NULL terminated array. + * @deep_copied: if %TRUE, clones the individual strings. In that case, + * the returned array must be freed with g_strfreev(). Otherwise, the + * strings themself are not copied. You must take care of who owns the + * strings yourself. * * Like g_strdupv(), with two differences: * @@ -2384,10 +2595,13 @@ nm_utils_strv_make_deep_copied_n (const char **strv, gsize len) * array with g_strfreev(). Allowing that would be error prone. * * Returns: (transfer full): a clone of the strv array. Always - * %NULL terminated. + * %NULL terminated. Depending on @deep_copied, the strings are + * cloned or not. */ char ** -nm_utils_strv_dup (gpointer strv, gssize len) +nm_utils_strv_dup (gpointer strv, + gssize len, + gboolean deep_copied) { gsize i, l; char **v; @@ -2415,7 +2629,10 @@ nm_utils_strv_dup (gpointer strv, gssize len) g_return_val_if_reached (v); } - v[i] = g_strdup (src[i]); + if (deep_copied) + v[i] = g_strdup (src[i]); + else + v[i] = (char *) src[i]; } v[l] = NULL; return v; @@ -2657,7 +2874,9 @@ nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid) g_return_val_if_fail (pid > 0, 0); - nm_sprintf_buf (filename, "/proc/%"G_GUINT64_FORMAT"/stat", (guint64) pid); + G_STATIC_ASSERT_EXPR (sizeof (GPid) >= sizeof (pid_t)); + + nm_sprintf_buf (filename, "/proc/%"G_PID_FORMAT"/stat", (GPid) pid); if (!g_file_get_contents (filename, &contents, &length, NULL)) goto fail; @@ -2845,6 +3064,24 @@ nm_utils_g_slist_strlist_cmp (const GSList *a, const GSList *b) } } +char * +nm_utils_g_slist_strlist_join (const GSList *a, const char *separator) +{ + GString *str = NULL; + + if (!a) + return NULL; + + for (; a; a = a->next) { + if (!str) + str = g_string_new (NULL); + else + g_string_append (str, separator); + g_string_append (str, a->data); + } + return g_string_free (str, FALSE); +} + /*****************************************************************************/ gpointer @@ -3275,3 +3512,478 @@ nm_utils_gvariant_vardict_filter_drop_one (GVariant *src, _gvariant_vardict_filter_drop_one, (gpointer) key); } + +/*****************************************************************************/ + +static gboolean +debug_key_matches (const char *key, + const char *token, + guint length) +{ + /* may not call GLib functions: see note in g_parse_debug_string() */ + for (; length; length--, key++, token++) { + char k = (*key == '_') ? '-' : g_ascii_tolower (*key ); + char t = (*token == '_') ? '-' : g_ascii_tolower (*token); + + if (k != t) + return FALSE; + } + + return *key == '\0'; +} + +/** + * nm_utils_parse_debug_string: + * @string: the string to parse + * @keys: the debug keys + * @nkeys: number of entries in @keys + * + * Similar to g_parse_debug_string(), but does not special + * case "help" or "all". + * + * Returns: the flags + */ +guint +nm_utils_parse_debug_string (const char *string, + const GDebugKey *keys, + guint nkeys) +{ + guint i; + guint result = 0; + const char *q; + + if (string == NULL) + return 0; + + while (*string) { + q = strpbrk (string, ":;, \t"); + if (!q) + q = string + strlen (string); + + for (i = 0; i < nkeys; i++) { + if (debug_key_matches (keys[i].key, string, q - string)) + result |= keys[i].value; + } + + string = q; + if (*string) + string++; + } + + return result; +} + +/*****************************************************************************/ + +GSource * +nm_g_idle_source_new (int priority, + GSourceFunc func, + gpointer user_data, + GDestroyNotify destroy_notify) +{ + GSource *source; + + source = g_idle_source_new (); + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority (source, priority); + g_source_set_callback (source, func, user_data, destroy_notify); + return source; +} + +GSource * +nm_g_timeout_source_new (guint timeout_ms, + int priority, + GSourceFunc func, + gpointer user_data, + GDestroyNotify destroy_notify) +{ + GSource *source; + + source = g_timeout_source_new (timeout_ms); + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority (source, priority); + g_source_set_callback (source, func, user_data, destroy_notify); + return source; +} + +GSource * +nm_g_unix_signal_source_new (int signum, + int priority, + GSourceFunc handler, + gpointer user_data, + GDestroyNotify notify) +{ + GSource *source; + + source = g_unix_signal_source_new (signum); + + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority (source, priority); + g_source_set_callback (source, handler, user_data, notify); + return source; +} + +/*****************************************************************************/ + +#define _CTX_LOG(fmt, ...) \ + G_STMT_START { \ + if (FALSE) { \ + gint64 _ts = g_get_monotonic_time () / 100; \ + \ + g_printerr (">>>> [%"G_GINT64_FORMAT".%05"G_GINT64_FORMAT"] [src:%p]: " fmt "\n", \ + _ts / 10000, \ + _ts % 10000, \ + (ctx_src), \ + ##__VA_ARGS__); \ + } \ + } G_STMT_END + +typedef struct { + int fd; + guint events; + guint registered_events; + union { + int one; + int *many; + } idx; + gpointer tag; + bool stale:1; + bool has_many_idx:1; +} PollData; + +typedef struct { + GSource source; + GMainContext *context; + GHashTable *fds; + GPollFD *fds_arr; + int fds_len; + int max_priority; + bool acquired:1; +} CtxIntegSource; + +static void +_poll_data_free (gpointer user_data) +{ + PollData *poll_data = user_data; + + if (poll_data->has_many_idx) + g_free (poll_data->idx.many); + nm_g_slice_free (poll_data); +} + +static void +_ctx_integ_source_reacquire (CtxIntegSource *ctx_src) +{ + if (G_LIKELY ( ctx_src->acquired + && g_main_context_is_owner (ctx_src->context))) + return; + + /* the parent context now iterates on a different thread. + * We need to release and reacquire the inner context. */ + + if (ctx_src->acquired) + g_main_context_release (ctx_src->context); + + if (G_UNLIKELY (!g_main_context_acquire (ctx_src->context))) { + /* Nobody is supposed to reacquire the context while we use it. This is a bug + * of the user. */ + ctx_src->acquired = FALSE; + g_return_if_reached (); + } + ctx_src->acquired = TRUE; +} + +static gboolean +_ctx_integ_source_prepare (GSource *source, + int *out_timeout) +{ + CtxIntegSource *ctx_src = ((CtxIntegSource *) source); + int max_priority; + int timeout = -1; + gboolean any_ready; + int fds_allocated; + int fds_len_old; + gs_free GPollFD *fds_arr_old = NULL; + GHashTableIter h_iter; + PollData *poll_data; + gboolean fds_changed; + int i; + + _CTX_LOG ("prepare..."); + + _ctx_integ_source_reacquire (ctx_src); + + any_ready = g_main_context_prepare (ctx_src->context, &max_priority); + + fds_arr_old = g_steal_pointer (&ctx_src->fds_arr); + fds_len_old = ctx_src->fds_len; + + fds_allocated = NM_MAX (1, fds_len_old); /* there is at least the wakeup's FD */ + ctx_src->fds_arr = g_new (GPollFD, fds_allocated); + + while ((ctx_src->fds_len = g_main_context_query (ctx_src->context, + max_priority, + &timeout, + ctx_src->fds_arr, + fds_allocated)) > fds_allocated) { + fds_allocated = ctx_src->fds_len; + g_free (ctx_src->fds_arr); + ctx_src->fds_arr = g_new (GPollFD, fds_allocated); + } + + fds_changed = FALSE; + if (fds_len_old != ctx_src->fds_len) + fds_changed = TRUE; + else { + for (i = 0; i < ctx_src->fds_len; i++) { + if ( fds_arr_old[i].fd != ctx_src->fds_arr[i].fd + || fds_arr_old[i].events != ctx_src->fds_arr[i].events) { + fds_changed = TRUE; + break; + } + } + } + + if (G_UNLIKELY (fds_changed)) { + + g_hash_table_iter_init (&h_iter, ctx_src->fds); + while (g_hash_table_iter_next (&h_iter, (gpointer *) &poll_data, NULL)) + poll_data->stale = TRUE; + + for (i = 0; i < ctx_src->fds_len; i++) { + const GPollFD *fd = &ctx_src->fds_arr[i]; + + poll_data = g_hash_table_lookup (ctx_src->fds, &fd->fd); + + if (G_UNLIKELY (!poll_data)) { + poll_data = g_slice_new (PollData); + *poll_data = (PollData) { + .fd = fd->fd, + .idx.one = i, + .has_many_idx = FALSE, + .events = fd->events, + .registered_events = 0, + .tag = NULL, + .stale = FALSE, + }; + g_hash_table_add (ctx_src->fds, poll_data); + nm_assert (poll_data == g_hash_table_lookup (ctx_src->fds, &fd->fd)); + continue; + } + + if (G_LIKELY (poll_data->stale)) { + if (poll_data->has_many_idx) { + g_free (poll_data->idx.many); + poll_data->has_many_idx = FALSE; + } + poll_data->events = fd->events; + poll_data->idx.one = i; + poll_data->stale = FALSE; + continue; + } + + /* How odd. We have duplicate FDs. In fact, currently g_main_context_query() always + * coalesces the FDs and this cannot happen. However, that is not documented behavior, + * so we should not rely on that. So we need to keep a list of indexes... */ + poll_data->events |= fd->events; + if (!poll_data->has_many_idx) { + int idx0; + + idx0 = poll_data->idx.one; + poll_data->has_many_idx = TRUE; + poll_data->idx.many = g_new (int, 4); + poll_data->idx.many[0] = 2; /* number allocated */ + poll_data->idx.many[1] = 2; /* number used */ + poll_data->idx.many[2] = idx0; + poll_data->idx.many[3] = i; + } else { + if (poll_data->idx.many[0] == poll_data->idx.many[1]) { + poll_data->idx.many[0] *= 2; + poll_data->idx.many = g_realloc (poll_data->idx.many, sizeof (int) * (2 + poll_data->idx.many[0])); + } + poll_data->idx.many[2 + poll_data->idx.many[1]] = i; + poll_data->idx.many[1]++; + } + + } + + g_hash_table_iter_init (&h_iter, ctx_src->fds); + while (g_hash_table_iter_next (&h_iter, (gpointer *) &poll_data, NULL)) { + if (poll_data->stale) { + nm_assert (poll_data->tag); + nm_assert (poll_data->events == poll_data->registered_events); + _CTX_LOG ("prepare: remove poll fd=%d, events=0x%x", poll_data->fd, poll_data->events); + g_source_remove_unix_fd (&ctx_src->source, poll_data->tag); + g_hash_table_iter_remove (&h_iter); + continue; + } + if (!poll_data->tag) { + _CTX_LOG ("prepare: add poll fd=%d, events=0x%x", poll_data->fd, poll_data->events); + poll_data->registered_events = poll_data->events; + poll_data->tag = g_source_add_unix_fd (&ctx_src->source, poll_data->fd, poll_data->registered_events); + continue; + } + if (poll_data->registered_events != poll_data->events) { + _CTX_LOG ("prepare: update poll fd=%d, events=0x%x", poll_data->fd, poll_data->events); + poll_data->registered_events = poll_data->events; + g_source_modify_unix_fd (&ctx_src->source, poll_data->tag, poll_data->registered_events); + } + } + } + + NM_SET_OUT (out_timeout, timeout); + ctx_src->max_priority = max_priority; + + _CTX_LOG ("prepare: done, any-ready=%d, timeout=%d, max-priority=%d", any_ready, timeout, max_priority); + + /* we always need to poll, because we have some file descriptors. */ + return FALSE; +} + +static gboolean +_ctx_integ_source_check (GSource *source) +{ + CtxIntegSource *ctx_src = ((CtxIntegSource *) source); + GHashTableIter h_iter; + gboolean some_ready; + PollData *poll_data; + + nm_assert (ctx_src->context); + + _CTX_LOG ("check"); + + _ctx_integ_source_reacquire (ctx_src); + + g_hash_table_iter_init (&h_iter, ctx_src->fds); + while (g_hash_table_iter_next (&h_iter, (gpointer *) &poll_data, NULL)) { + guint revents; + + revents = g_source_query_unix_fd (&ctx_src->source, poll_data->tag); + if (G_UNLIKELY (poll_data->has_many_idx)) { + int num = poll_data->idx.many[1]; + int *p_idx = &poll_data->idx.many[2]; + + for (; num > 0; num--, p_idx++) + ctx_src->fds_arr[*p_idx].revents = revents; + } else + ctx_src->fds_arr[poll_data->idx.one].revents = revents; + } + + some_ready = g_main_context_check (ctx_src->context, + ctx_src->max_priority, + ctx_src->fds_arr, + ctx_src->fds_len); + + _CTX_LOG ("check (some-ready=%d)...", some_ready); + + return some_ready; +} + +static gboolean +_ctx_integ_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + CtxIntegSource *ctx_src = ((CtxIntegSource *) source); + + nm_assert (ctx_src->context); + + _ctx_integ_source_reacquire (ctx_src); + + _CTX_LOG ("dispatch"); + + g_main_context_dispatch (ctx_src->context); + + return G_SOURCE_CONTINUE; +} + +static void +_ctx_integ_source_finalize (GSource *source) +{ + CtxIntegSource *ctx_src = ((CtxIntegSource *) source); + GHashTableIter h_iter; + PollData *poll_data; + + g_return_if_fail (ctx_src->context); + + _CTX_LOG ("finalize..."); + + g_hash_table_iter_init (&h_iter, ctx_src->fds); + while (g_hash_table_iter_next (&h_iter, (gpointer *) &poll_data, NULL)) { + nm_assert (poll_data->tag); + _CTX_LOG ("prepare: remove poll fd=%d, events=0x%x", poll_data->fd, poll_data->events); + g_source_remove_unix_fd (&ctx_src->source, poll_data->tag); + g_hash_table_iter_remove (&h_iter); + } + + nm_clear_pointer (&ctx_src->fds, g_hash_table_unref); + nm_clear_g_free (&ctx_src->fds_arr); + ctx_src->fds_len = 0; + + if (ctx_src->acquired) { + ctx_src->acquired = FALSE; + g_main_context_release (ctx_src->context); + } + + nm_clear_pointer (&ctx_src->context, g_main_context_unref); +} + +static GSourceFuncs ctx_integ_source_funcs = { + .prepare = _ctx_integ_source_prepare, + .check = _ctx_integ_source_check, + .dispatch = _ctx_integ_source_dispatch, + .finalize = _ctx_integ_source_finalize, +}; + +/** + * nm_utils_g_main_context_create_integrate_source: + * @inner_context: the inner context that will be integrated to an + * outer #GMainContext. + * + * By integrating the inner context with an outer context, when iterating the outer + * context sources on the inner context will be dispatched. Note that while the + * created source exists, the @inner_context will be acquired. The user gets restricted + * what to do with the inner context. In particular while the inner context is integrated, + * the user should not acquire the inner context again or explicitly iterate it. What + * the user of course still can (and wants to) do is attaching new sources to the inner + * context. + * + * Note that GSource has a priority. While each context dispatches events based on + * their source's priorities, the outer context dispatches to the inner context + * only with one priority (the priority of the created source). That is, the sources + * from the two contexts are kept separate and are not sorted by their priorities. + * + * Returns: a newly created GSource that should be attached to the + * outer context. + */ +GSource * +nm_utils_g_main_context_create_integrate_source (GMainContext *inner_context) +{ + CtxIntegSource *ctx_src; + + g_return_val_if_fail (inner_context, NULL); + + if (!g_main_context_acquire (inner_context)) { + /* We require to acquire the context while it's integrated. We need to keep it acquired + * for the entire duration. + * + * This is also necessary because g_source_attach() only wakes up the context, if + * the context is currently acquired. */ + g_return_val_if_reached (NULL); + } + + ctx_src = (CtxIntegSource *) g_source_new (&ctx_integ_source_funcs, sizeof (CtxIntegSource)); + + g_source_set_name (&ctx_src->source, "ContextIntegrateSource"); + + ctx_src->context = g_main_context_ref (inner_context); + ctx_src->fds = g_hash_table_new_full (nm_pint_hash, nm_pint_equals, _poll_data_free, NULL); + ctx_src->fds_len = 0; + ctx_src->fds_arr = NULL; + ctx_src->acquired = TRUE; + ctx_src->max_priority = G_MAXINT; + + _CTX_LOG ("create new integ-source for %p", inner_context); + + return &ctx_src->source; +} diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index d9c430d4..3bd1afae 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1,21 +1,6 @@ -/* 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 2016 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2016 Red Hat, Inc. */ #ifndef __NM_SHARED_UTILS_H__ @@ -104,6 +89,16 @@ nm_utils_addr_family_to_size (int addr_family) g_return_val_if_reached (0); } +static inline int +nm_utils_addr_family_from_size (gsize len) +{ + switch (len) { + case sizeof (in_addr_t): return AF_INET; + case sizeof (struct in6_addr): return AF_INET6; + } + return AF_UNSPEC; +} + #define nm_assert_addr_family(addr_family) \ nm_assert (NM_IN_SET ((addr_family), AF_INET, AF_INET6)) @@ -537,15 +532,29 @@ nm_utils_escaped_tokens_escape_gstr (const char *str, guint32 _nm_utils_ip4_prefix_to_netmask (guint32 prefix); guint32 _nm_utils_ip4_get_default_prefix (guint32 ip); +gconstpointer nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer src, guint8 plen); +in_addr_t nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen); +const struct in6_addr *nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen); +int nm_utils_ip6_address_same_prefix_cmp (const struct in6_addr *addr_a, const struct in6_addr *addr_b, guint8 plen); + gboolean nm_utils_ip_is_site_local (int addr_family, const void *address); /*****************************************************************************/ -gboolean nm_utils_parse_inaddr_bin (int addr_family, - const char *text, - int *out_addr_family, - gpointer out_addr); +gboolean nm_utils_parse_inaddr_bin_full (int addr_family, + gboolean accept_legacy, + const char *text, + int *out_addr_family, + gpointer out_addr); +static inline gboolean +nm_utils_parse_inaddr_bin (int addr_family, + const char *text, + int *out_addr_family, + gpointer out_addr) +{ + return nm_utils_parse_inaddr_bin_full (addr_family, FALSE, text, out_addr_family, out_addr); +} gboolean nm_utils_parse_inaddr (int addr_family, const char *text, @@ -652,8 +661,9 @@ _nm_g_slice_free_fcn_define (8) _nm_g_slice_free_fcn_define (10) _nm_g_slice_free_fcn_define (12) _nm_g_slice_free_fcn_define (16) +_nm_g_slice_free_fcn_define (32) -#define _nm_g_slice_free_fcn1(mem_size) \ +#define nm_g_slice_free_fcn1(mem_size) \ ({ \ void (*_fcn) (gpointer); \ \ @@ -666,7 +676,8 @@ _nm_g_slice_free_fcn_define (16) || ((mem_size) == 8) \ || ((mem_size) == 10) \ || ((mem_size) == 12) \ - || ((mem_size) == 16)); \ + || ((mem_size) == 16) \ + || ((mem_size) == 32)); \ switch ((mem_size)) { \ case 1: _fcn = _nm_g_slice_free_fcn_1; break; \ case 2: _fcn = _nm_g_slice_free_fcn_2; break; \ @@ -675,6 +686,7 @@ _nm_g_slice_free_fcn_define (16) case 10: _fcn = _nm_g_slice_free_fcn_10; break; \ case 12: _fcn = _nm_g_slice_free_fcn_12; break; \ case 16: _fcn = _nm_g_slice_free_fcn_16; break; \ + case 32: _fcn = _nm_g_slice_free_fcn_32; break; \ default: g_assert_not_reached (); _fcn = NULL; break; \ } \ _fcn; \ @@ -688,14 +700,38 @@ _nm_g_slice_free_fcn_define (16) * Returns: a function pointer with GDestroyNotify signature * for g_slice_free(type,*). * - * Only certain types are implemented. You'll get an assertion - * using the wrong type. */ -#define nm_g_slice_free_fcn(type) (_nm_g_slice_free_fcn1 (sizeof (type))) + * Only certain types are implemented. You'll get a compile time + * error for the wrong types. */ +#define nm_g_slice_free_fcn(type) (nm_g_slice_free_fcn1 (sizeof (type))) #define nm_g_slice_free_fcn_gint64 (nm_g_slice_free_fcn (gint64)) /*****************************************************************************/ +static inline void +nm_g_set_error_take (GError **error, GError *error_take) +{ + if (!error_take) + g_return_if_reached (); + if (!error) { + g_error_free (error_take); + return; + } + if (*error) { + g_error_free (error_take); + g_return_if_reached (); + } + *error = error_take; +} + +#define nm_g_set_error_take_lazy(error, error_take_lazy) \ + G_STMT_START { \ + GError **_error = (error); \ + \ + if (_error) \ + nm_g_set_error_take (_error, (error_take_lazy)); \ + } G_STMT_END + /** * NMUtilsError: * @NM_UTILS_ERROR_UNKNOWN: unknown or unclassified error @@ -750,6 +786,17 @@ GQuark nm_utils_error_quark (void); void nm_utils_error_set_cancelled (GError **error, gboolean is_disposing, const char *instance_name); + +static inline GError * +nm_utils_error_new_cancelled (gboolean is_disposing, + const char *instance_name) +{ + GError *error = NULL; + + nm_utils_error_set_cancelled (&error, is_disposing, instance_name); + return error; +} + gboolean nm_utils_error_is_cancelled (GError *error, gboolean consider_is_disposing); @@ -792,6 +839,11 @@ nm_utils_error_set_literal (GError **error, int error_code, const char *literal) sizeof (_bstrerr))); \ } G_STMT_END +#define nm_utils_error_new(error_code, ...) \ + ( (NM_NARG (__VA_ARGS__) == 1) \ + ? g_error_new_literal (NM_UTILS_ERROR, (error_code), _NM_UTILS_MACRO_FIRST (__VA_ARGS__)) \ + : g_error_new (NM_UTILS_ERROR, (error_code), __VA_ARGS__)) + /*****************************************************************************/ gboolean nm_g_object_set_property (GObject *object, @@ -906,6 +958,82 @@ nm_g_variant_unref_floating (GVariant *var) g_variant_unref (var); } +static inline void +nm_g_source_destroy_and_unref (GSource *source) +{ + g_source_destroy (source); + g_source_unref (source); +} + +#define nm_clear_g_source_inst(ptr) (nm_clear_pointer ((ptr), nm_g_source_destroy_and_unref)) + +NM_AUTO_DEFINE_FCN0 (GSource *, _nm_auto_destroy_and_unref_gsource, nm_g_source_destroy_and_unref); +#define nm_auto_destroy_and_unref_gsource nm_auto(_nm_auto_destroy_and_unref_gsource) + +NM_AUTO_DEFINE_FCN0 (GMainContext *, _nm_auto_pop_gmaincontext, g_main_context_pop_thread_default) +#define nm_auto_pop_gmaincontext nm_auto (_nm_auto_pop_gmaincontext) + +GSource *nm_g_idle_source_new (int priority, + GSourceFunc func, + gpointer user_data, + GDestroyNotify destroy_notify); + +GSource *nm_g_timeout_source_new (guint timeout_ms, + int priority, + GSourceFunc func, + gpointer user_data, + GDestroyNotify destroy_notify); + +GSource *nm_g_unix_signal_source_new (int signum, + int priority, + GSourceFunc handler, + gpointer user_data, + GDestroyNotify notify); + +static inline GSource * +nm_g_source_attach (GSource *source, + GMainContext *context) +{ + g_source_attach (source, context); + return source; +} + +NM_AUTO_DEFINE_FCN0 (GMainContext *, _nm_auto_unref_gmaincontext, g_main_context_unref) +#define nm_auto_unref_gmaincontext nm_auto (_nm_auto_unref_gmaincontext) + +static inline GMainContext * +nm_g_main_context_push_thread_default (GMainContext *context) +{ + /* This function is to work together with nm_auto_pop_gmaincontext. */ + if (G_UNLIKELY (!context)) + context = g_main_context_default (); + g_main_context_push_thread_default (context); + return context; +} + +static inline GMainContext * +nm_g_main_context_push_thread_default_if_necessary (GMainContext *context) +{ + GMainContext *cur_context; + + cur_context = g_main_context_get_thread_default (); + if (cur_context == context) + return NULL; + + if (G_UNLIKELY (!cur_context)) { + cur_context = g_main_context_default (); + if (cur_context == context) + return NULL; + } else if (G_UNLIKELY (!context)) { + context = g_main_context_default (); + if (cur_context == context) + return NULL; + } + + g_main_context_push_thread_default (context); + return context; +} + /*****************************************************************************/ static inline int @@ -966,6 +1094,11 @@ gpointer *nm_utils_hash_keys_to_array (GHashTable *hash, gpointer user_data, guint *out_len); +gpointer *nm_utils_hash_values_to_array (GHashTable *hash, + GCompareDataFunc compare_func, + gpointer user_data, + guint *out_len); + static inline const char ** nm_utils_strdict_get_keys (const GHashTable *hash, gboolean sorted, @@ -990,7 +1123,9 @@ nm_utils_strv_make_deep_copied_nonnull (const char **strv) return nm_utils_strv_make_deep_copied (strv) ?: g_new0 (char *, 1); } -char **nm_utils_strv_dup (gpointer strv, gssize len); +char **nm_utils_strv_dup (gpointer strv, + gssize len, + gboolean deep_copied); /*****************************************************************************/ @@ -999,6 +1134,8 @@ GSList *nm_utils_g_slist_find_str (const GSList *list, int nm_utils_g_slist_strlist_cmp (const GSList *a, const GSList *b); +char *nm_utils_g_slist_strlist_join (const GSList *a, const char *separator); + /*****************************************************************************/ gssize nm_utils_ptrarray_find_binary_search (gconstpointer *list, @@ -1160,6 +1297,15 @@ nm_utils_dbus_normalize_object_path (const char *path) guint64 nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid); +static inline gboolean +nm_utils_process_state_is_dead (char pstate) +{ + /* "/proc/[pid]/stat" returns a state as the 3rd fields (see `man 5 proc`). + * Some of these states indicate the the process is effectively dead (or a zombie). + */ + return NM_IN_SET (pstate, 'Z', 'x', 'X'); +} + /*****************************************************************************/ gpointer _nm_utils_user_data_pack (int nargs, gconstpointer *args); @@ -1183,6 +1329,10 @@ void nm_utils_invoke_on_idle (NMUtilsInvokeOnIdleCallback callback, /*****************************************************************************/ +GSource *nm_utils_g_main_context_create_integrate_source (GMainContext *internal); + +/*****************************************************************************/ + static inline void nm_strv_ptrarray_add_string_take (GPtrArray *cmd, char *str) @@ -1252,4 +1402,34 @@ guint8 *nm_utils_hexstr2bin_alloc (const char *hexstr, gsize required_len, gsize *out_len); +/*****************************************************************************/ + +static inline GTask * +nm_g_task_new (gpointer source_object, + GCancellable *cancellable, + gpointer source_tag, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + GTask *task; + + task = g_task_new (source_object, cancellable, callback, callback_data); + if (source_tag) + g_task_set_source_tag (task, source_tag); + return task; +} + +static inline gboolean +nm_g_task_is_valid (gpointer task, + gpointer source_object, + gpointer source_tag) +{ + return g_task_is_valid (task, source_object) + && g_task_get_source_tag (task) == source_tag; +} + +guint nm_utils_parse_debug_string (const char *string, + const GDebugKey *keys, + guint nkeys); + #endif /* __NM_SHARED_UTILS_H__ */ diff --git a/shared/nm-glib-aux/nm-time-utils.c b/shared/nm-glib-aux/nm-time-utils.c index 7735f29d..20d663bc 100644 --- a/shared/nm-glib-aux/nm-time-utils.c +++ b/shared/nm-glib-aux/nm-time-utils.c @@ -1,21 +1,6 @@ -/* 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 2018 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -234,12 +219,17 @@ nm_utils_get_monotonic_timestamp_s (void) * @timestamp_ns_per_tick: How many nanoseconds make one unit of @timestamp? E.g. if * @timestamp is in unit seconds, pass %NM_UTILS_NS_PER_SECOND; if @timestamp is * in nanoseconds, pass 1; if @timestamp is in milliseconds, pass %NM_UTILS_NS_PER_SECOND/1000. + * This must be a multiple of 10, and between 1 and %NM_UTILS_NS_PER_SECOND. * * Returns: the monotonic-timestamp as CLOCK_BOOTTIME, as returned by clock_gettime(). * The unit is the same as the passed in @timestamp based on @timestamp_ns_per_tick. * E.g. if you passed @timestamp in as seconds, it will return boottime in seconds. - * If @timestamp is non-positive, it returns -1. Note that a (valid) monotonic-timestamp - * is always positive. + * + * Note that valid monotonic-timestamps are always positive numbers (counting roughly since + * the application is running). However, it might make sense to calculate a timestamp from + * before the application was running, hence negative @timestamp is allowed. The result + * in that case might also be a negative timestamp (in CLOCK_BOOTTIME), which would indicate + * that the timestamp lies in the past before the machine was booted. * * On older kernels that don't support CLOCK_BOOTTIME, the returned time is instead CLOCK_MONOTONIC. **/ @@ -256,9 +246,6 @@ nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ns_ timestamp_ns_per_tick % 10 == 0), -1); - /* Check that the timestamp is in a valid range. */ - g_return_val_if_fail (timestamp >= 0, -1); - /* if the caller didn't yet ever fetch a monotonic-timestamp, he cannot pass any meaningful * value (because he has no idea what these timestamps would be). That would be a bug. */ nm_assert (g_atomic_pointer_get (&p_global_state)); @@ -270,12 +257,60 @@ nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ns_ /* calculate the offset of monotonic-timestamp to boottime. offset_s is <= 1. */ offset = p->offset_sec * (NM_UTILS_NS_PER_SECOND / timestamp_ns_per_tick); - /* check for overflow. */ - g_return_val_if_fail (offset > 0 || timestamp < G_MAXINT64 + offset, G_MAXINT64); + nm_assert (offset <= 0 && offset > G_MININT64); + + /* check for overflow (note that offset is non-positive). */ + g_return_val_if_fail (timestamp < G_MAXINT64 + offset, G_MAXINT64); return timestamp - offset; } +/** + * nm_utils_monotonic_timestamp_from_boottime: + * @boottime: the timestamp from CLOCK_BOOTTIME (or CLOCK_MONOTONIC, if + * kernel does not support CLOCK_BOOTTIME and monotonic timestamps are based + * on CLOCK_MONOTONIC). + * @timestamp_ns_per_tick: the scale in which @boottime is. If @boottime is in + * nano seconds, this should be 1. If it is in milli seconds, this should be + * %NM_UTILS_NS_PER_SECOND/1000, etc. + * + * Returns: the same timestamp in monotonic timestamp scale. + * + * Note that commonly monotonic timestamps are positive. But they may not + * be positive in this case. That's when boottime is taken from a time before + * the monotonic timestamps started counting. So, that means a zero or negative + * value is still a valid timestamp. + * + * This is the inverse of nm_utils_monotonic_timestamp_as_boottime(). + */ +gint64 +nm_utils_monotonic_timestamp_from_boottime (guint64 boottime, gint64 timestamp_ns_per_tick) +{ + const GlobalState *p; + gint64 offset; + + /* only support ns-per-tick being a multiple of 10. */ + g_return_val_if_fail (timestamp_ns_per_tick == 1 + || (timestamp_ns_per_tick > 0 && + timestamp_ns_per_tick <= NM_UTILS_NS_PER_SECOND && + timestamp_ns_per_tick % 10 == 0), + -1); + + p = _t_get_global_state (); + + nm_assert (p->offset_sec <= 0); + + /* calculate the offset of monotonic-timestamp to boottime. offset_s is <= 1. */ + offset = p->offset_sec * (NM_UTILS_NS_PER_SECOND / timestamp_ns_per_tick); + + nm_assert (offset <= 0 && offset > G_MININT64); + + /* check for overflow (note that offset is non-positive). */ + g_return_val_if_fail (boottime < G_MAXINT64, G_MAXINT64); + + return (gint64) boottime + offset; +} + gint64 nm_utils_clock_gettime_ns (clockid_t clockid) { diff --git a/shared/nm-glib-aux/nm-time-utils.h b/shared/nm-glib-aux/nm-time-utils.h index 52d6637d..8bf41b96 100644 --- a/shared/nm-glib-aux/nm-time-utils.h +++ b/shared/nm-glib-aux/nm-time-utils.h @@ -1,21 +1,6 @@ -/* 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 2018 Red Hat, Inc. +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2018 Red Hat, Inc. */ #ifndef __NM_TIME_UTILS_H__ @@ -42,6 +27,7 @@ gint64 nm_utils_get_monotonic_timestamp_us (void); gint64 nm_utils_get_monotonic_timestamp_ms (void); gint32 nm_utils_get_monotonic_timestamp_s (void); gint64 nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ticks_per_ns); +gint64 nm_utils_monotonic_timestamp_from_boottime (guint64 boottime, gint64 timestamp_ns_per_tick); static inline gint64 nm_utils_get_monotonic_timestamp_ns_cached (gint64 *cache_now) diff --git a/shared/nm-glib-aux/nm-value-type.h b/shared/nm-glib-aux/nm-value-type.h index b4d6898f..6fe6f072 100644 --- a/shared/nm-glib-aux/nm-value-type.h +++ b/shared/nm-glib-aux/nm-value-type.h @@ -1,20 +1,6 @@ +// SPDX-License-Identifier: LGPL-2.1+ /* - * 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. - * - * Copyright 2019 Red Hat, Inc. + * Copyright (C) 2019 Red Hat, Inc. */ #ifndef __NM_VALUE_TYPE_H__ |