summaryrefslogtreecommitdiff
path: root/shared/nm-utils/nm-udev-utils.c
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-03-12 15:54:02 +0100
committerThomas Haller <thaller@redhat.com>2017-03-22 12:41:06 +0100
commite32839838e5ea74ba490cf912e20939afa0e4f40 (patch)
tree2df2c623a8448078f8b0ee67359718cc7eee747c /shared/nm-utils/nm-udev-utils.c
parentedaa7d064e5efef2abcb08d44355a2a8f5a09e87 (diff)
downloadNetworkManager-e32839838e5ea74ba490cf912e20939afa0e4f40.tar.gz
udev: drop libgudev in favor of libudev
libgudev is just a wrapper around libudev. We can use libudev directly and drop the dependency for libgudev.
Diffstat (limited to 'shared/nm-utils/nm-udev-utils.c')
-rw-r--r--shared/nm-utils/nm-udev-utils.c240
1 files changed, 240 insertions, 0 deletions
diff --git a/shared/nm-utils/nm-udev-utils.c b/shared/nm-utils/nm-udev-utils.c
new file mode 100644
index 0000000000..22d98037c7
--- /dev/null
+++ b/shared/nm-utils/nm-udev-utils.c
@@ -0,0 +1,240 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* nm-udev-utils.c - udev utils functions
+ *
+ * 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, 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 (C) 2017 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-udev-utils.h"
+
+#include <libudev.h>
+
+struct _NMPUdevClient {
+ char **subsystems;
+ GSource *watch_source;
+ struct udev *udev;
+ struct udev_monitor *monitor;
+ NMUdevClientEvent event_handler;
+ gpointer event_user_data;
+};
+
+/*****************************************************************************/
+
+gboolean
+nm_udev_utils_property_as_boolean (const char *uproperty)
+{
+ /* taken from g_udev_device_get_property_as_boolean() */
+
+ if (uproperty) {
+ if ( strcmp (uproperty, "1") == 0
+ || g_ascii_strcasecmp (uproperty, "true") == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static void
+_subsystem_split (const char *subsystem_full,
+ const char **out_subsystem,
+ const char **out_devtype,
+ char **to_free)
+{
+ char *tmp, *s;
+
+ nm_assert (subsystem_full);
+ nm_assert (out_subsystem);
+ nm_assert (out_devtype);
+ nm_assert (to_free);
+
+ s = strstr (subsystem_full, "/");
+ if (s) {
+ tmp = g_strdup (subsystem_full);
+ s = &tmp[s - subsystem_full];
+ *s = '\0';
+ *out_subsystem = tmp;
+ *out_devtype = &s[1];
+ *to_free = tmp;
+ } else {
+ *out_subsystem = subsystem_full;
+ *out_devtype = NULL;
+ *to_free = NULL;
+ }
+}
+
+static struct udev_enumerate *
+nm_udev_utils_enumerate (struct udev *uclient,
+ const char *const*subsystems)
+{
+ struct udev_enumerate *enumerate;
+ guint n;
+
+ enumerate = udev_enumerate_new (uclient);
+
+ if (subsystems) {
+ for (n = 0; subsystems[n]; n++) {
+ const char *subsystem;
+ const char *devtype;
+ gs_free char *to_free;
+
+ _subsystem_split (subsystems[n], &subsystem, &devtype, &to_free);
+
+ udev_enumerate_add_match_subsystem (enumerate, subsystem);
+
+ if (devtype != NULL)
+ udev_enumerate_add_match_property (enumerate, "DEVTYPE", devtype);
+ }
+ }
+
+ return enumerate;
+}
+
+struct udev *
+nm_udev_client_get_udev (NMUdevClient *self)
+{
+ g_return_val_if_fail (self, NULL);
+
+ return self->udev;
+}
+
+struct udev_enumerate *
+nm_udev_client_enumerate_new (NMUdevClient *self)
+{
+ g_return_val_if_fail (self, NULL);
+
+ return nm_udev_utils_enumerate (self->udev, (const char *const*) self->subsystems);
+}
+
+/*****************************************************************************/
+
+static gboolean
+monitor_event (GIOChannel *source,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ NMUdevClient *self = user_data;
+ struct udev_device *udevice;
+
+ if (!self->monitor)
+ goto out;
+
+ if (!self->event_handler)
+ goto out;
+
+ udevice = udev_monitor_receive_device (self->monitor);
+ if (udevice == NULL)
+ goto out;
+
+ self->event_handler (self,
+ udevice,
+ self->event_user_data);
+ udev_device_unref (udevice);
+
+out:
+ return TRUE;
+}
+
+/**
+ * nm_udev_client_new:
+ * @subsystems: the subsystems
+ * @event_handler: callback for events
+ * @event_user_data: user-data for @event_handler
+ *
+ * Basically, it is g_udev_client_new(), and most notably
+ * g_udev_client_constructed().
+ *
+ * Returns: a new NMUdevClient instance.
+ */
+NMUdevClient *
+nm_udev_client_new (const char *const*subsystems,
+ NMUdevClientEvent event_handler,
+ gpointer event_user_data)
+{
+ NMUdevClient *self;
+ GIOChannel *channel;
+ guint n;
+
+ self = g_slice_new0 (NMUdevClient);
+
+ self->event_handler = event_handler;
+ self->event_user_data = event_user_data;
+ self->subsystems = subsystems && subsystems[0] ? g_strdupv ((char **) subsystems) : NULL;
+
+ self->udev = udev_new ();
+ if (!self->udev)
+ goto fail;
+
+ /* connect to event source */
+ self->monitor = udev_monitor_new_from_netlink (self->udev, "udev");
+ if (!self->monitor)
+ goto fail;
+
+ if (self->subsystems) {
+ /* install subsystem filters to only wake up for certain events */
+ for (n = 0; self->subsystems[n]; n++) {
+ if (self->monitor) {
+ gs_free char *to_free;
+ const char *subsystem;
+ const char *devtype;
+
+ _subsystem_split (self->subsystems[n], &subsystem, &devtype, &to_free);
+ udev_monitor_filter_add_match_subsystem_devtype (self->monitor, subsystem, devtype);
+ }
+ }
+
+ /* listen to events, and buffer them */
+ if (self->monitor) {
+ udev_monitor_enable_receiving (self->monitor);
+ channel = g_io_channel_unix_new (udev_monitor_get_fd (self->monitor));
+ self->watch_source = g_io_create_watch (channel, G_IO_IN);
+ g_io_channel_unref (channel);
+ g_source_set_callback (self->watch_source, (GSourceFunc) monitor_event, self, NULL);
+ g_source_attach (self->watch_source, g_main_context_get_thread_default ());
+ g_source_unref (self->watch_source);
+ }
+ }
+
+ return self;
+
+fail:
+ return nm_udev_client_unref (self);
+}
+
+NMUdevClient *
+nm_udev_client_unref (NMUdevClient *self)
+{
+ if (!self)
+ return NULL;
+
+ if (self->watch_source) {
+ g_source_destroy (self->watch_source);
+ self->watch_source = NULL;
+ }
+
+ udev_monitor_unref (self->monitor);
+ self->monitor = NULL;
+ udev_unref (self->udev);
+ self->udev = NULL;
+
+ g_strfreev (self->subsystems);
+
+ g_slice_free (NMUdevClient, self);
+
+ return NULL;
+}