Blame src/nm-dbus-utils.c

Packit Service b23acc
// SPDX-License-Identifier: GPL-2.0+
Packit Service b23acc
/*
Packit Service b23acc
 * Copyright (C) 2018 Red Hat, Inc.
Packit Service b23acc
 */
Packit Service b23acc
Packit Service b23acc
#include "nm-default.h"
Packit Service b23acc
Packit Service b23acc
#include "nm-dbus-utils.h"
Packit Service b23acc
Packit Service b23acc
#include "nm-dbus-object.h"
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
const GDBusSignalInfo nm_signal_info_property_changed_legacy = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT (
Packit Service b23acc
	"PropertiesChanged",
Packit Service b23acc
	.args = NM_DEFINE_GDBUS_ARG_INFOS (
Packit Service b23acc
		NM_DEFINE_GDBUS_ARG_INFO ("properties", "a{sv}"),
Packit Service b23acc
	),
Packit Service b23acc
);
Packit Service b23acc
Packit Service b23acc
GDBusPropertyInfo *
Packit Service b23acc
nm_dbus_utils_interface_info_lookup_property (const GDBusInterfaceInfo *interface_info,
Packit Service b23acc
                                              const char *property_name,
Packit Service b23acc
                                              guint *property_idx)
Packit Service b23acc
{
Packit Service b23acc
	guint i;
Packit Service b23acc
Packit Service b23acc
	nm_assert (interface_info);
Packit Service b23acc
	nm_assert (property_name);
Packit Service b23acc
Packit Service b23acc
	/* there is also g_dbus_interface_info_lookup_property(), however that makes use
Packit Service b23acc
	 * of a global cache. */
Packit Service b23acc
	if (interface_info->properties) {
Packit Service b23acc
		for (i = 0; interface_info->properties[i]; i++) {
Packit Service b23acc
			GDBusPropertyInfo *info = interface_info->properties[i];
Packit Service b23acc
Packit Service b23acc
			if (nm_streq (info->name, property_name)) {
Packit Service b23acc
				NM_SET_OUT (property_idx, i);
Packit Service b23acc
				return info;
Packit Service b23acc
			}
Packit Service b23acc
		}
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	return NULL;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
GDBusMethodInfo *
Packit Service b23acc
nm_dbus_utils_interface_info_lookup_method (const GDBusInterfaceInfo *interface_info,
Packit Service b23acc
                                            const char *method_name)
Packit Service b23acc
{
Packit Service b23acc
	guint i;
Packit Service b23acc
Packit Service b23acc
	nm_assert (interface_info);
Packit Service b23acc
	nm_assert (method_name);
Packit Service b23acc
Packit Service b23acc
	/* there is also g_dbus_interface_info_lookup_property(), however that makes use
Packit Service b23acc
	 * of a global cache. */
Packit Service b23acc
	if (interface_info->methods) {
Packit Service b23acc
		for (i = 0; interface_info->methods[i]; i++) {
Packit Service b23acc
			GDBusMethodInfo *info = interface_info->methods[i];
Packit Service b23acc
Packit Service b23acc
			if (nm_streq (info->name, method_name))
Packit Service b23acc
				return info;
Packit Service b23acc
		}
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	return NULL;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
GVariant *
Packit Service b23acc
nm_dbus_utils_get_property (GObject *obj,
Packit Service b23acc
                            const char *signature,
Packit Service b23acc
                            const char *property_name)
Packit Service b23acc
{
Packit Service b23acc
	GParamSpec *pspec;
Packit Service b23acc
	nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
Packit Service b23acc
Packit Service b23acc
	nm_assert (G_IS_OBJECT (obj));
Packit Service b23acc
	nm_assert (g_variant_type_string_is_valid (signature));
Packit Service b23acc
	nm_assert (property_name && property_name[0]);
Packit Service b23acc
Packit Service b23acc
	pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), property_name);
Packit Service b23acc
	if (!pspec)
Packit Service b23acc
		g_return_val_if_reached (NULL);
Packit Service b23acc
Packit Service b23acc
	g_value_init (&value, pspec->value_type);
Packit Service b23acc
	g_object_get_property (obj, property_name, &value);
Packit Service b23acc
	/* returns never-floating variant */
Packit Service b23acc
	return g_dbus_gvalue_to_gvariant (&value, G_VARIANT_TYPE (signature));
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_dbus_utils_g_value_set_object_path (GValue *value, gpointer object)
Packit Service b23acc
{
Packit Service b23acc
	const char *path;
Packit Service b23acc
Packit Service b23acc
	g_return_if_fail (!object || NM_IS_DBUS_OBJECT (object));
Packit Service b23acc
Packit Service b23acc
	if (   object
Packit Service b23acc
	    && (path = nm_dbus_object_get_path (object)))
Packit Service b23acc
		g_value_set_string (value, path);
Packit Service b23acc
	else
Packit Service b23acc
		g_value_set_string (value, NULL);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_dbus_utils_g_value_set_object_path_still_exported (GValue *value, gpointer object)
Packit Service b23acc
{
Packit Service b23acc
	const char *path;
Packit Service b23acc
Packit Service b23acc
	g_return_if_fail (!object || NM_IS_DBUS_OBJECT (object));
Packit Service b23acc
Packit Service b23acc
	if (   object
Packit Service b23acc
	    && (path = nm_dbus_object_get_path_still_exported (object)))
Packit Service b23acc
		g_value_set_string (value, path);
Packit Service b23acc
	else
Packit Service b23acc
		g_value_set_string (value, "/");
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_dbus_utils_g_value_set_object_path_from_hash (GValue *value,
Packit Service b23acc
                                                 GHashTable *hash /* has keys of NMDBusObject type. */,
Packit Service b23acc
                                                 gboolean expect_all_exported)
Packit Service b23acc
{
Packit Service b23acc
	NMDBusObject *obj;
Packit Service b23acc
	char **strv;
Packit Service b23acc
	guint i, n;
Packit Service b23acc
	GHashTableIter iter;
Packit Service b23acc
Packit Service b23acc
	nm_assert (value);
Packit Service b23acc
	nm_assert (hash);
Packit Service b23acc
Packit Service b23acc
	n = g_hash_table_size (hash);
Packit Service b23acc
	strv = g_new (char *, n + 1);
Packit Service b23acc
	i = 0;
Packit Service b23acc
	g_hash_table_iter_init (&iter, hash);
Packit Service b23acc
	while (g_hash_table_iter_next (&iter, (gpointer *) &obj, NULL)) {
Packit Service b23acc
		const char *path;
Packit Service b23acc
Packit Service b23acc
		path = nm_dbus_object_get_path_still_exported (obj);
Packit Service b23acc
		if (!path) {
Packit Service b23acc
			nm_assert (!expect_all_exported);
Packit Service b23acc
			continue;
Packit Service b23acc
		}
Packit Service b23acc
		strv[i++] = g_strdup (path);
Packit Service b23acc
	}
Packit Service b23acc
	nm_assert (i <= n);
Packit Service b23acc
	strv[i] = NULL;
Packit Service b23acc
Packit Service b23acc
	/* sort the names, to give a well-defined, stable order. */
Packit Service b23acc
	nm_utils_strv_sort (strv, i);
Packit Service b23acc
Packit Service b23acc
	g_value_take_boxed (value, strv);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
const char **
Packit Service b23acc
nm_dbus_utils_get_paths_for_clist (const CList *lst_head,
Packit Service b23acc
                                   gssize lst_len,
Packit Service b23acc
                                   guint member_offset,
Packit Service b23acc
                                   gboolean expect_all_exported)
Packit Service b23acc
{
Packit Service b23acc
	const CList *iter;
Packit Service b23acc
	const char **strv;
Packit Service b23acc
	const char *path;
Packit Service b23acc
	gsize i, n;
Packit Service b23acc
Packit Service b23acc
	nm_assert (lst_head);
Packit Service b23acc
Packit Service b23acc
	if (lst_len < 0)
Packit Service b23acc
		n = c_list_length (lst_head);
Packit Service b23acc
	else {
Packit Service b23acc
		n = lst_len;
Packit Service b23acc
		nm_assert (n == c_list_length (lst_head));
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	i = 0;
Packit Service b23acc
	strv = g_new (const char *, n + 1);
Packit Service b23acc
	c_list_for_each (iter, lst_head) {
Packit Service b23acc
		NMDBusObject *obj = (NMDBusObject *) (((const char *) iter) - member_offset);
Packit Service b23acc
Packit Service b23acc
		path = nm_dbus_object_get_path (obj);
Packit Service b23acc
		if (!path) {
Packit Service b23acc
			nm_assert (expect_all_exported);
Packit Service b23acc
			continue;
Packit Service b23acc
		}
Packit Service b23acc
Packit Service b23acc
		nm_assert (i < n);
Packit Service b23acc
		strv[i++] = path;
Packit Service b23acc
	}
Packit Service b23acc
	nm_assert (i <= n);
Packit Service b23acc
	strv[i] = NULL;
Packit Service b23acc
Packit Service b23acc
	return strv;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_dbus_track_obj_path_init (NMDBusTrackObjPath *track,
Packit Service b23acc
                             GObject *target,
Packit Service b23acc
                             const GParamSpec *pspec)
Packit Service b23acc
{
Packit Service b23acc
	nm_assert (track);
Packit Service b23acc
	nm_assert (G_IS_OBJECT (target));
Packit Service b23acc
	nm_assert (G_IS_PARAM_SPEC (pspec));
Packit Service b23acc
Packit Service b23acc
	track->_obj = NULL;
Packit Service b23acc
	track->_notify_target = target;
Packit Service b23acc
	track->_notify_pspec = pspec;
Packit Service b23acc
	track->_notify_signal_id = 0;
Packit Service b23acc
	track->_visible = FALSE;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_dbus_track_obj_path_deinit (NMDBusTrackObjPath *track)
Packit Service b23acc
{
Packit Service b23acc
	/* we allow deinit() to be called multiple times (e.g. from
Packit Service b23acc
	 * dispose(), which must be re-entrant). */
Packit Service b23acc
	nm_assert (track);
Packit Service b23acc
	nm_assert (!track->_notify_target || G_IS_OBJECT (track->_notify_target));
Packit Service b23acc
Packit Service b23acc
	nm_clear_g_signal_handler (track->obj, &track->_notify_signal_id);
Packit Service b23acc
	track->_notify_target = NULL;
Packit Service b23acc
	track->_notify_pspec = NULL;
Packit Service b23acc
	track->_visible = FALSE;
Packit Service b23acc
	nm_clear_g_object (&track->_obj);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_dbus_track_obj_path_notify (const NMDBusTrackObjPath *track)
Packit Service b23acc
{
Packit Service b23acc
	nm_assert (track);
Packit Service b23acc
	nm_assert (G_IS_OBJECT (track->_notify_target));
Packit Service b23acc
	nm_assert (G_IS_PARAM_SPEC (track->_notify_pspec));
Packit Service b23acc
Packit Service b23acc
	g_object_notify_by_pspec (track->_notify_target,
Packit Service b23acc
	                          (GParamSpec *) track->_notify_pspec);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
const char *
Packit Service b23acc
nm_dbus_track_obj_path_get (const NMDBusTrackObjPath *track)
Packit Service b23acc
{
Packit Service b23acc
	nm_assert (track);
Packit Service b23acc
	nm_assert (G_IS_OBJECT (track->_notify_target));
Packit Service b23acc
Packit Service b23acc
	return track->obj && track->visible
Packit Service b23acc
	       ? nm_dbus_object_get_path_still_exported (track->obj)
Packit Service b23acc
	       : NULL;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_track_obj_exported_changed (NMDBusObject *obj,
Packit Service b23acc
                             NMDBusTrackObjPath *track)
Packit Service b23acc
{
Packit Service b23acc
	nm_dbus_track_obj_path_notify (track);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_dbus_track_obj_path_set (NMDBusTrackObjPath *track,
Packit Service b23acc
                            gpointer obj,
Packit Service b23acc
                            gboolean visible)
Packit Service b23acc
{
Packit Service b23acc
	gs_unref_object NMDBusObject *old_obj = NULL;
Packit Service b23acc
	const char *old_path;
Packit Service b23acc
Packit Service b23acc
	nm_assert (track);
Packit Service b23acc
	nm_assert (G_IS_OBJECT (track->_notify_target));
Packit Service b23acc
Packit Service b23acc
	g_return_if_fail (!obj || NM_IS_DBUS_OBJECT (obj));
Packit Service b23acc
Packit Service b23acc
	if (   track->obj == obj
Packit Service b23acc
	    && track->visible == !!visible)
Packit Service b23acc
		return;
Packit Service b23acc
Packit Service b23acc
	old_path = nm_dbus_track_obj_path_get (track);
Packit Service b23acc
Packit Service b23acc
	track->_visible = visible;
Packit Service b23acc
Packit Service b23acc
	if (track->obj != obj) {
Packit Service b23acc
		nm_clear_g_signal_handler (track->obj, &track->_notify_signal_id);
Packit Service b23acc
Packit Service b23acc
		old_obj = track->obj;
Packit Service b23acc
		track->_obj = nm_g_object_ref (obj);
Packit Service b23acc
Packit Service b23acc
		if (obj) {
Packit Service b23acc
			track->_notify_signal_id = g_signal_connect (obj,
Packit Service b23acc
			                                             NM_DBUS_OBJECT_EXPORTED_CHANGED,
Packit Service b23acc
			                                             G_CALLBACK (_track_obj_exported_changed),
Packit Service b23acc
			                                             track);
Packit Service b23acc
		}
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	if (!nm_streq0 (old_path, nm_dbus_track_obj_path_get (track)))
Packit Service b23acc
		nm_dbus_track_obj_path_notify (track);
Packit Service b23acc
}