summaryrefslogtreecommitdiff
path: root/src/libnm-udev-aux
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-02-18 08:13:35 +0100
committerThomas Haller <thaller@redhat.com>2021-02-24 12:48:19 +0100
commit4d12a6ac3dd48c606ff45a65bf0e8d2fd5655894 (patch)
tree55a925e255b8edc76421450113618ddb5a94300e /src/libnm-udev-aux
parent174bd45344b8c1d6f41c2c5541dedbd7731ea485 (diff)
downloadNetworkManager-4d12a6ac3dd48c606ff45a65bf0e8d2fd5655894.tar.gz
build: move "shared/nm-{base,udev-aux}" to "src/libnm-{base,udev-aux}"
Diffstat (limited to 'src/libnm-udev-aux')
-rw-r--r--src/libnm-udev-aux/meson.build15
-rw-r--r--src/libnm-udev-aux/nm-udev-utils.c265
-rw-r--r--src/libnm-udev-aux/nm-udev-utils.h33
3 files changed, 313 insertions, 0 deletions
diff --git a/src/libnm-udev-aux/meson.build b/src/libnm-udev-aux/meson.build
new file mode 100644
index 0000000000..4577a83a93
--- /dev/null
+++ b/src/libnm-udev-aux/meson.build
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+libnm_udev_aux = static_library(
+ 'nm-udev-aux',
+ sources: 'nm-udev-utils.c',
+ dependencies: [
+ glib_nm_default_dep,
+ libudev_dep,
+ ],
+)
+
+libnm_udev_aux_dep = declare_dependency(
+ include_directories: shared_inc,
+ link_with: libnm_udev_aux,
+)
diff --git a/src/libnm-udev-aux/nm-udev-utils.c b/src/libnm-udev-aux/nm-udev-utils.c
new file mode 100644
index 0000000000..0b941dff53
--- /dev/null
+++ b/src/libnm-udev-aux/nm-udev-utils.c
@@ -0,0 +1,265 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ */
+
+#include "nm-glib-aux/nm-default-glib-i18n-lib.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;
+}
+
+const char *
+nm_udev_utils_property_decode(const char *uproperty, char **to_free)
+{
+ const char *p;
+ char * unescaped = NULL;
+ char * n = NULL;
+
+ if (!uproperty) {
+ *to_free = NULL;
+ return NULL;
+ }
+
+ p = uproperty;
+ while (*p) {
+ int a, b;
+
+ if (p[0] == '\\' && p[1] == 'x' && (a = g_ascii_xdigit_value(p[2])) >= 0
+ && (b = g_ascii_xdigit_value(p[3])) >= 0 && (a || b)) {
+ if (!n) {
+ gssize l = p - uproperty;
+
+ unescaped = g_malloc(l + strlen(p) + 1 - 3);
+ memcpy(unescaped, uproperty, l);
+ n = &unescaped[l];
+ }
+ *n++ = (a << 4) | b;
+ p += 4;
+ } else {
+ if (n)
+ *n++ = *p;
+ p++;
+ }
+ }
+
+ if (!n) {
+ *to_free = NULL;
+ return uproperty;
+ }
+
+ *n++ = '\0';
+ return (*to_free = unescaped);
+}
+
+char *
+nm_udev_utils_property_decode_cp(const char *uproperty)
+{
+ char *cpy;
+
+ uproperty = nm_udev_utils_property_decode(uproperty, &cpy);
+ return cpy ?: g_strdup(uproperty);
+}
+
+/*****************************************************************************/
+
+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 = NULL;
+
+ _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(int fd, GIOCondition condition, gpointer user_data)
+{
+ NMUdevClient * self = user_data;
+ struct udev_device *udevice;
+
+ if (!self->monitor)
+ 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;
+ 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 */
+ if (self->event_handler) {
+ 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++) {
+ gs_free char *to_free = NULL;
+ 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 */
+ udev_monitor_set_receive_buffer_size(self->monitor, 4 * 1024 * 1024);
+ udev_monitor_enable_receiving(self->monitor);
+
+ self->watch_source = nm_g_unix_fd_source_new(udev_monitor_get_fd(self->monitor),
+ G_IO_IN,
+ G_PRIORITY_DEFAULT,
+ monitor_event,
+ self,
+ NULL);
+ g_source_attach(self->watch_source, g_main_context_get_thread_default());
+ }
+ }
+
+ return self;
+
+fail:
+ return nm_udev_client_destroy(self);
+}
+
+NMUdevClient *
+nm_udev_client_destroy(NMUdevClient *self)
+{
+ if (!self)
+ return NULL;
+
+ nm_clear_g_source_inst(&self->watch_source);
+
+ 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;
+}
diff --git a/src/libnm-udev-aux/nm-udev-utils.h b/src/libnm-udev-aux/nm-udev-utils.h
new file mode 100644
index 0000000000..191f9a89a4
--- /dev/null
+++ b/src/libnm-udev-aux/nm-udev-utils.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ */
+
+#ifndef __NM_UDEV_UTILS_H__
+#define __NM_UDEV_UTILS_H__
+
+struct udev;
+struct udev_device;
+struct udev_enumerate;
+
+gboolean nm_udev_utils_property_as_boolean(const char *uproperty);
+const char *nm_udev_utils_property_decode(const char *uproperty, char **to_free);
+char * nm_udev_utils_property_decode_cp(const char *uproperty);
+
+typedef struct _NMPUdevClient NMUdevClient;
+
+typedef void (*NMUdevClientEvent)(NMUdevClient * udev_client,
+ struct udev_device *udevice,
+ gpointer event_user_data);
+
+NMUdevClient *nm_udev_client_new(const char *const *subsystems,
+ NMUdevClientEvent event_handler,
+ gpointer event_user_data);
+
+NMUdevClient *nm_udev_client_destroy(NMUdevClient *self);
+
+struct udev *nm_udev_client_get_udev(NMUdevClient *self);
+
+struct udev_enumerate *nm_udev_client_enumerate_new(NMUdevClient *self);
+
+#endif /* __NM_UDEV_UTILS_H__ */