summaryrefslogtreecommitdiff
path: root/src/gudev
diff options
context:
space:
mode:
Diffstat (limited to 'src/gudev')
-rw-r--r--src/gudev/.gitignore7
l---------src/gudev/Makefile1
-rwxr-xr-xsrc/gudev/gjs-example.js75
-rw-r--r--src/gudev/gudev-1.0.pc.in11
-rw-r--r--src/gudev/gudev.h33
-rw-r--r--src/gudev/gudevclient.c527
-rw-r--r--src/gudev/gudevclient.h100
-rw-r--r--src/gudev/gudevdevice.c963
-rw-r--r--src/gudev/gudevdevice.h128
-rw-r--r--src/gudev/gudevenumerator.c431
-rw-r--r--src/gudev/gudevenumerator.h107
-rw-r--r--src/gudev/gudevenums.h49
-rw-r--r--src/gudev/gudevenumtypes.c.template39
-rw-r--r--src/gudev/gudevenumtypes.h.template24
-rw-r--r--src/gudev/gudevmarshal.list1
-rw-r--r--src/gudev/gudevprivate.h41
-rw-r--r--src/gudev/gudevtypes.h51
-rwxr-xr-xsrc/gudev/seed-example-enum.js38
-rwxr-xr-xsrc/gudev/seed-example.js72
19 files changed, 2698 insertions, 0 deletions
diff --git a/src/gudev/.gitignore b/src/gudev/.gitignore
new file mode 100644
index 0000000000..4577903c40
--- /dev/null
+++ b/src/gudev/.gitignore
@@ -0,0 +1,7 @@
+gudev-1.0.pc
+gudevenumtypes.c
+gudevenumtypes.h
+gudevmarshal.c
+gudevmarshal.h
+GUdev-1.0.gir
+GUdev-1.0.typelib
diff --git a/src/gudev/Makefile b/src/gudev/Makefile
new file mode 120000
index 0000000000..d0b0e8e008
--- /dev/null
+++ b/src/gudev/Makefile
@@ -0,0 +1 @@
+../Makefile \ No newline at end of file
diff --git a/src/gudev/gjs-example.js b/src/gudev/gjs-example.js
new file mode 100755
index 0000000000..5586fd6a61
--- /dev/null
+++ b/src/gudev/gjs-example.js
@@ -0,0 +1,75 @@
+#!/usr/bin/env gjs-console
+
+// This currently depends on the following patches to gjs
+//
+// http://bugzilla.gnome.org/show_bug.cgi?id=584558
+// http://bugzilla.gnome.org/show_bug.cgi?id=584560
+// http://bugzilla.gnome.org/show_bug.cgi?id=584568
+
+const GUdev = imports.gi.GUdev;
+const Mainloop = imports.mainloop;
+
+function print_device (device) {
+ print (" subsystem: " + device.get_subsystem ());
+ print (" devtype: " + device.get_devtype ());
+ print (" name: " + device.get_name ());
+ print (" number: " + device.get_number ());
+ print (" sysfs_path: " + device.get_sysfs_path ());
+ print (" driver: " + device.get_driver ());
+ print (" action: " + device.get_action ());
+ print (" seqnum: " + device.get_seqnum ());
+ print (" device type: " + device.get_device_type ());
+ print (" device number: " + device.get_device_number ());
+ print (" device file: " + device.get_device_file ());
+ print (" device file symlinks: " + device.get_device_file_symlinks ());
+ print (" foo: " + device.get_sysfs_attr_as_strv ("stat"));
+ var keys = device.get_property_keys ();
+ for (var n = 0; n < keys.length; n++) {
+ print (" " + keys[n] + "=" + device.get_property (keys[n]));
+ }
+}
+
+function on_uevent (client, action, device) {
+ print ("action " + action + " on device " + device.get_sysfs_path());
+ print_device (device);
+ print ("");
+}
+
+var client = new GUdev.Client ({subsystems: ["block", "usb/usb_interface"]});
+client.connect ("uevent", on_uevent);
+
+var block_devices = client.query_by_subsystem ("block");
+for (var n = 0; n < block_devices.length; n++) {
+ print ("block device: " + block_devices[n].get_device_file ());
+}
+
+var d;
+
+d = client.query_by_device_number (GUdev.DeviceType.BLOCK, 0x0810);
+if (d == null) {
+ print ("query_by_device_number 0x810 -> null");
+} else {
+ print ("query_by_device_number 0x810 -> " + d.get_device_file ());
+ var dd = d.get_parent_with_subsystem ("usb", null);
+ print_device (dd);
+ print ("--------------------------------------------------------------------------");
+ while (d != null) {
+ print_device (d);
+ print ("");
+ d = d.get_parent ();
+ }
+}
+
+d = client.query_by_sysfs_path ("/sys/block/sda/sda1");
+print ("query_by_sysfs_path (\"/sys/block/sda1\") -> " + d.get_device_file ());
+
+d = client.query_by_subsystem_and_name ("block", "sda2");
+print ("query_by_subsystem_and_name (\"block\", \"sda2\") -> " + d.get_device_file ());
+
+d = client.query_by_device_file ("/dev/sda");
+print ("query_by_device_file (\"/dev/sda\") -> " + d.get_device_file ());
+
+d = client.query_by_device_file ("/dev/block/8:0");
+print ("query_by_device_file (\"/dev/block/8:0\") -> " + d.get_device_file ());
+
+Mainloop.run('udev-example');
diff --git a/src/gudev/gudev-1.0.pc.in b/src/gudev/gudev-1.0.pc.in
new file mode 100644
index 0000000000..058262d767
--- /dev/null
+++ b/src/gudev/gudev-1.0.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: gudev-1.0
+Description: GObject bindings for libudev
+Version: @VERSION@
+Requires: glib-2.0, gobject-2.0
+Libs: -L${libdir} -lgudev-1.0
+Cflags: -I${includedir}/gudev-1.0
diff --git a/src/gudev/gudev.h b/src/gudev/gudev.h
new file mode 100644
index 0000000000..6ae01f2bf1
--- /dev/null
+++ b/src/gudev/gudev.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_UDEV_H__
+#define __G_UDEV_H__
+
+#define _GUDEV_INSIDE_GUDEV_H
+#include <gudev/gudevenums.h>
+#include <gudev/gudevenumtypes.h>
+#include <gudev/gudevtypes.h>
+#include <gudev/gudevclient.h>
+#include <gudev/gudevdevice.h>
+#include <gudev/gudevenumerator.h>
+#undef _GUDEV_INSIDE_GUDEV_H
+
+#endif /* __G_UDEV_H__ */
diff --git a/src/gudev/gudevclient.c b/src/gudev/gudevclient.c
new file mode 100644
index 0000000000..2b94102ac5
--- /dev/null
+++ b/src/gudev/gudevclient.c
@@ -0,0 +1,527 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gudevclient.h"
+#include "gudevdevice.h"
+#include "gudevmarshal.h"
+#include "gudevprivate.h"
+
+/**
+ * SECTION:gudevclient
+ * @short_description: Query devices and listen to uevents
+ *
+ * #GUdevClient is used to query information about devices on a Linux
+ * system from the Linux kernel and the udev device
+ * manager.
+ *
+ * Device information is retrieved from the kernel (through the
+ * <literal>sysfs</literal> filesystem) and the udev daemon (through a
+ * <literal>tmpfs</literal> filesystem) and presented through
+ * #GUdevDevice objects. This means that no blocking IO ever happens
+ * (in both cases, we are essentially just reading data from kernel
+ * memory) and as such there are no asynchronous versions of the
+ * provided methods.
+ *
+ * To get #GUdevDevice objects, use
+ * g_udev_client_query_by_subsystem(),
+ * g_udev_client_query_by_device_number(),
+ * g_udev_client_query_by_device_file(),
+ * g_udev_client_query_by_sysfs_path(),
+ * g_udev_client_query_by_subsystem_and_name()
+ * or the #GUdevEnumerator type.
+ *
+ * To listen to uevents, connect to the #GUdevClient::uevent signal.
+ */
+
+struct _GUdevClientPrivate
+{
+ GSource *watch_source;
+ struct udev *udev;
+ struct udev_monitor *monitor;
+
+ gchar **subsystems;
+};
+
+enum
+{
+ PROP_0,
+ PROP_SUBSYSTEMS,
+};
+
+enum
+{
+ UEVENT_SIGNAL,
+ LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GUdevClient, g_udev_client, G_TYPE_OBJECT)
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+monitor_event (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ GUdevClient *client = (GUdevClient *) data;
+ GUdevDevice *device;
+ struct udev_device *udevice;
+
+ if (client->priv->monitor == NULL)
+ goto out;
+ udevice = udev_monitor_receive_device (client->priv->monitor);
+ if (udevice == NULL)
+ goto out;
+
+ device = _g_udev_device_new (udevice);
+ udev_device_unref (udevice);
+ g_signal_emit (client,
+ signals[UEVENT_SIGNAL],
+ 0,
+ g_udev_device_get_action (device),
+ device);
+ g_object_unref (device);
+
+ out:
+ return TRUE;
+}
+
+static void
+g_udev_client_finalize (GObject *object)
+{
+ GUdevClient *client = G_UDEV_CLIENT (object);
+
+ if (client->priv->watch_source != NULL)
+ {
+ g_source_destroy (client->priv->watch_source);
+ client->priv->watch_source = NULL;
+ }
+
+ if (client->priv->monitor != NULL)
+ {
+ udev_monitor_unref (client->priv->monitor);
+ client->priv->monitor = NULL;
+ }
+
+ if (client->priv->udev != NULL)
+ {
+ udev_unref (client->priv->udev);
+ client->priv->udev = NULL;
+ }
+
+ g_strfreev (client->priv->subsystems);
+
+ if (G_OBJECT_CLASS (g_udev_client_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (g_udev_client_parent_class)->finalize (object);
+}
+
+static void
+g_udev_client_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GUdevClient *client = G_UDEV_CLIENT (object);
+
+ switch (prop_id)
+ {
+ case PROP_SUBSYSTEMS:
+ if (client->priv->subsystems != NULL)
+ g_strfreev (client->priv->subsystems);
+ client->priv->subsystems = g_strdupv (g_value_get_boxed (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_udev_client_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GUdevClient *client = G_UDEV_CLIENT (object);
+
+ switch (prop_id)
+ {
+ case PROP_SUBSYSTEMS:
+ g_value_set_boxed (value, client->priv->subsystems);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_udev_client_constructed (GObject *object)
+{
+ GUdevClient *client = G_UDEV_CLIENT (object);
+ GIOChannel *channel;
+ guint n;
+
+ client->priv->udev = udev_new ();
+
+ /* connect to event source */
+ client->priv->monitor = udev_monitor_new_from_netlink (client->priv->udev, "udev");
+
+ //g_debug ("ss = %p", client->priv->subsystems);
+
+ if (client->priv->subsystems != NULL)
+ {
+ /* install subsystem filters to only wake up for certain events */
+ for (n = 0; client->priv->subsystems[n] != NULL; n++)
+ {
+ gchar *subsystem;
+ gchar *devtype;
+ gchar *s;
+
+ subsystem = g_strdup (client->priv->subsystems[n]);
+ devtype = NULL;
+
+ //g_debug ("s = '%s'", subsystem);
+
+ s = strstr (subsystem, "/");
+ if (s != NULL)
+ {
+ devtype = s + 1;
+ *s = '\0';
+ }
+
+ if (client->priv->monitor != NULL)
+ udev_monitor_filter_add_match_subsystem_devtype (client->priv->monitor, subsystem, devtype);
+
+ g_free (subsystem);
+ }
+
+ /* listen to events, and buffer them */
+ if (client->priv->monitor != NULL)
+ {
+ udev_monitor_enable_receiving (client->priv->monitor);
+ channel = g_io_channel_unix_new (udev_monitor_get_fd (client->priv->monitor));
+ client->priv->watch_source = g_io_create_watch (channel, G_IO_IN);
+ g_io_channel_unref (channel);
+ g_source_set_callback (client->priv->watch_source, (GSourceFunc) monitor_event, client, NULL);
+ g_source_attach (client->priv->watch_source, g_main_context_get_thread_default ());
+ g_source_unref (client->priv->watch_source);
+ }
+ else
+ {
+ client->priv->watch_source = NULL;
+ }
+ }
+
+ if (G_OBJECT_CLASS (g_udev_client_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (g_udev_client_parent_class)->constructed (object);
+}
+
+
+static void
+g_udev_client_class_init (GUdevClientClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+
+ gobject_class->constructed = g_udev_client_constructed;
+ gobject_class->set_property = g_udev_client_set_property;
+ gobject_class->get_property = g_udev_client_get_property;
+ gobject_class->finalize = g_udev_client_finalize;
+
+ /**
+ * GUdevClient:subsystems:
+ *
+ * The subsystems to listen for uevents on.
+ *
+ * To listen for only a specific DEVTYPE for a given SUBSYSTEM, use
+ * "subsystem/devtype". For example, to only listen for uevents
+ * where SUBSYSTEM is usb and DEVTYPE is usb_interface, use
+ * "usb/usb_interface".
+ *
+ * If this property is %NULL, then no events will be reported. If
+ * it's the empty array, events from all subsystems will be
+ * reported.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_SUBSYSTEMS,
+ g_param_spec_boxed ("subsystems",
+ "The subsystems to listen for changes on",
+ "The subsystems to listen for changes on",
+ G_TYPE_STRV,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE));
+
+ /**
+ * GUdevClient::uevent:
+ * @client: The #GUdevClient receiving the event.
+ * @action: The action for the uevent e.g. "add", "remove", "change", "move", etc.
+ * @device: Details about the #GUdevDevice the event is for.
+ *
+ * Emitted when @client receives an uevent.
+ *
+ * This signal is emitted in the
+ * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * of the thread that @client was created in.
+ */
+ signals[UEVENT_SIGNAL] = g_signal_new ("uevent",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GUdevClientClass, uevent),
+ NULL,
+ NULL,
+ g_udev_marshal_VOID__STRING_OBJECT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_UDEV_TYPE_DEVICE);
+
+ g_type_class_add_private (klass, sizeof (GUdevClientPrivate));
+}
+
+static void
+g_udev_client_init (GUdevClient *client)
+{
+ client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client,
+ G_UDEV_TYPE_CLIENT,
+ GUdevClientPrivate);
+}
+
+/**
+ * g_udev_client_new:
+ * @subsystems: (array zero-terminated=1) (element-type utf8) (transfer none) (allow-none): A %NULL terminated string array of subsystems to listen for uevents on, %NULL to not listen on uevents at all, or an empty array to listen to uevents on all subsystems. See the documentation for the #GUdevClient:subsystems property for details on this parameter.
+ *
+ * Constructs a #GUdevClient object that can be used to query
+ * information about devices. Connect to the #GUdevClient::uevent
+ * signal to listen for uevents. Note that signals are emitted in the
+ * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * of the thread that you call this constructor from.
+ *
+ * Returns: A new #GUdevClient object. Free with g_object_unref().
+ */
+GUdevClient *
+g_udev_client_new (const gchar * const *subsystems)
+{
+ return G_UDEV_CLIENT (g_object_new (G_UDEV_TYPE_CLIENT, "subsystems", subsystems, NULL));
+}
+
+/**
+ * g_udev_client_query_by_subsystem:
+ * @client: A #GUdevClient.
+ * @subsystem: (allow-none): The subsystem to get devices for or %NULL to get all devices.
+ *
+ * Gets all devices belonging to @subsystem.
+ *
+ * Returns: (element-type GUdevDevice) (transfer full): A list of #GUdevDevice objects. The caller should free the result by using g_object_unref() on each element in the list and then g_list_free() on the list.
+ */
+GList *
+g_udev_client_query_by_subsystem (GUdevClient *client,
+ const gchar *subsystem)
+{
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *l, *devices;
+ GList *ret;
+
+ g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
+
+ ret = NULL;
+
+ /* prepare a device scan */
+ enumerate = udev_enumerate_new (client->priv->udev);
+
+ /* filter for subsystem */
+ if (subsystem != NULL)
+ udev_enumerate_add_match_subsystem (enumerate, subsystem);
+ /* retrieve the list */
+ udev_enumerate_scan_devices (enumerate);
+
+ /* add devices to the list */
+ devices = udev_enumerate_get_list_entry (enumerate);
+ for (l = devices; l != NULL; l = udev_list_entry_get_next (l))
+ {
+ struct udev_device *udevice;
+ GUdevDevice *device;
+
+ udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate),
+ udev_list_entry_get_name (l));
+ if (udevice == NULL)
+ continue;
+ device = _g_udev_device_new (udevice);
+ udev_device_unref (udevice);
+ ret = g_list_prepend (ret, device);
+ }
+ udev_enumerate_unref (enumerate);
+
+ ret = g_list_reverse (ret);
+
+ return ret;
+}
+
+/**
+ * g_udev_client_query_by_device_number:
+ * @client: A #GUdevClient.
+ * @type: A value from the #GUdevDeviceType enumeration.
+ * @number: A device number.
+ *
+ * Looks up a device for a type and device number.
+ *
+ * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref().
+ */
+GUdevDevice *
+g_udev_client_query_by_device_number (GUdevClient *client,
+ GUdevDeviceType type,
+ GUdevDeviceNumber number)
+{
+ struct udev_device *udevice;
+ GUdevDevice *device;
+
+ g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
+
+ device = NULL;
+ udevice = udev_device_new_from_devnum (client->priv->udev, type, number);
+
+ if (udevice == NULL)
+ goto out;
+
+ device = _g_udev_device_new (udevice);
+ udev_device_unref (udevice);
+
+ out:
+ return device;
+}
+
+/**
+ * g_udev_client_query_by_device_file:
+ * @client: A #GUdevClient.
+ * @device_file: A device file.
+ *
+ * Looks up a device for a device file.
+ *
+ * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref().
+ */
+GUdevDevice *
+g_udev_client_query_by_device_file (GUdevClient *client,
+ const gchar *device_file)
+{
+ struct stat stat_buf;
+ GUdevDevice *device;
+
+ g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
+ g_return_val_if_fail (device_file != NULL, NULL);
+
+ device = NULL;
+
+ if (stat (device_file, &stat_buf) != 0)
+ goto out;
+
+ if (stat_buf.st_rdev == 0)
+ goto out;
+
+ if (S_ISBLK (stat_buf.st_mode))
+ device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_BLOCK, stat_buf.st_rdev);
+ else if (S_ISCHR (stat_buf.st_mode))
+ device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_CHAR, stat_buf.st_rdev);
+
+ out:
+ return device;
+}
+
+/**
+ * g_udev_client_query_by_sysfs_path:
+ * @client: A #GUdevClient.
+ * @sysfs_path: A sysfs path.
+ *
+ * Looks up a device for a sysfs path.
+ *
+ * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref().
+ */
+GUdevDevice *
+g_udev_client_query_by_sysfs_path (GUdevClient *client,
+ const gchar *sysfs_path)
+{
+ struct udev_device *udevice;
+ GUdevDevice *device;
+
+ g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
+ g_return_val_if_fail (sysfs_path != NULL, NULL);
+
+ device = NULL;
+ udevice = udev_device_new_from_syspath (client->priv->udev, sysfs_path);
+ if (udevice == NULL)
+ goto out;
+
+ device = _g_udev_device_new (udevice);
+ udev_device_unref (udevice);
+
+ out:
+ return device;
+}
+
+/**
+ * g_udev_client_query_by_subsystem_and_name:
+ * @client: A #GUdevClient.
+ * @subsystem: A subsystem name.
+ * @name: The name of the device.
+ *
+ * Looks up a device for a subsystem and name.
+ *
+ * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref().
+ */
+GUdevDevice *
+g_udev_client_query_by_subsystem_and_name (GUdevClient *client,
+ const gchar *subsystem,
+ const gchar *name)
+{
+ struct udev_device *udevice;
+ GUdevDevice *device;
+
+ g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
+ g_return_val_if_fail (subsystem != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ device = NULL;
+ udevice = udev_device_new_from_subsystem_sysname (client->priv->udev, subsystem, name);
+ if (udevice == NULL)
+ goto out;
+
+ device = _g_udev_device_new (udevice);
+ udev_device_unref (udevice);
+
+ out:
+ return device;
+}
+
+struct udev *
+_g_udev_client_get_udev (GUdevClient *client)
+{
+ g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
+ return client->priv->udev;
+}
diff --git a/src/gudev/gudevclient.h b/src/gudev/gudevclient.h
new file mode 100644
index 0000000000..b425d03d48
--- /dev/null
+++ b/src/gudev/gudevclient.h
@@ -0,0 +1,100 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
+#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __G_UDEV_CLIENT_H__
+#define __G_UDEV_CLIENT_H__
+
+#include <gudev/gudevtypes.h>
+
+G_BEGIN_DECLS
+
+#define G_UDEV_TYPE_CLIENT (g_udev_client_get_type ())
+#define G_UDEV_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_CLIENT, GUdevClient))
+#define G_UDEV_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_CLIENT, GUdevClientClass))
+#define G_UDEV_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_CLIENT))
+#define G_UDEV_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_CLIENT))
+#define G_UDEV_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_CLIENT, GUdevClientClass))
+
+typedef struct _GUdevClientClass GUdevClientClass;
+typedef struct _GUdevClientPrivate GUdevClientPrivate;
+
+/**
+ * GUdevClient:
+ *
+ * The #GUdevClient struct is opaque and should not be accessed directly.
+ */
+struct _GUdevClient
+{
+ GObject parent;
+
+ /*< private >*/
+ GUdevClientPrivate *priv;
+};
+
+/**
+ * GUdevClientClass:
+ * @parent_class: Parent class.
+ * @uevent: Signal class handler for the #GUdevClient::uevent signal.
+ *
+ * Class structure for #GUdevClient.
+ */
+struct _GUdevClientClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*uevent) (GUdevClient *client,
+ const gchar *action,
+ GUdevDevice *device);
+
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*reserved1) (void);
+ void (*reserved2) (void);
+ void (*reserved3) (void);
+ void (*reserved4) (void);
+ void (*reserved5) (void);
+ void (*reserved6) (void);
+ void (*reserved7) (void);
+ void (*reserved8) (void);
+};
+
+GType g_udev_client_get_type (void) G_GNUC_CONST;
+GUdevClient *g_udev_client_new (const gchar* const *subsystems);
+GList *g_udev_client_query_by_subsystem (GUdevClient *client,
+ const gchar *subsystem);
+GUdevDevice *g_udev_client_query_by_device_number (GUdevClient *client,
+ GUdevDeviceType type,
+ GUdevDeviceNumber number);
+GUdevDevice *g_udev_client_query_by_device_file (GUdevClient *client,
+ const gchar *device_file);
+GUdevDevice *g_udev_client_query_by_sysfs_path (GUdevClient *client,
+ const gchar *sysfs_path);
+GUdevDevice *g_udev_client_query_by_subsystem_and_name (GUdevClient *client,
+ const gchar *subsystem,
+ const gchar *name);
+
+G_END_DECLS
+
+#endif /* __G_UDEV_CLIENT_H__ */
diff --git a/src/gudev/gudevdevice.c b/src/gudev/gudevdevice.c
new file mode 100644
index 0000000000..62a26f99b7
--- /dev/null
+++ b/src/gudev/gudevdevice.c
@@ -0,0 +1,963 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gudevdevice.h"
+#include "gudevprivate.h"
+
+/**
+ * SECTION:gudevdevice
+ * @short_description: Get information about a device
+ *
+ * The #GUdevDevice class is used to get information about a specific
+ * device. Note that you cannot instantiate a #GUdevDevice object
+ * yourself. Instead you must use #GUdevClient to obtain #GUdevDevice
+ * objects.
+ *
+ * To get basic information about a device, use
+ * g_udev_device_get_subsystem(), g_udev_device_get_devtype(),
+ * g_udev_device_get_name(), g_udev_device_get_number(),
+ * g_udev_device_get_sysfs_path(), g_udev_device_get_driver(),
+ * g_udev_device_get_action(), g_udev_device_get_seqnum(),
+ * g_udev_device_get_device_type(), g_udev_device_get_device_number(),
+ * g_udev_device_get_device_file(),
+ * g_udev_device_get_device_file_symlinks().
+ *
+ * To navigate the device tree, use g_udev_device_get_parent() and
+ * g_udev_device_get_parent_with_subsystem().
+ *
+ * To access udev properties for the device, use
+ * g_udev_device_get_property_keys(),
+ * g_udev_device_has_property(),
+ * g_udev_device_get_property(),
+ * g_udev_device_get_property_as_int(),
+ * g_udev_device_get_property_as_uint64(),
+ * g_udev_device_get_property_as_double(),
+ * g_udev_device_get_property_as_boolean() and
+ * g_udev_device_get_property_as_strv().
+ *
+ * To access sysfs attributes for the device, use
+ * g_udev_device_get_sysfs_attr(),
+ * g_udev_device_get_sysfs_attr_as_int(),
+ * g_udev_device_get_sysfs_attr_as_uint64(),
+ * g_udev_device_get_sysfs_attr_as_double(),
+ * g_udev_device_get_sysfs_attr_as_boolean() and
+ * g_udev_device_get_sysfs_attr_as_strv().
+ *
+ * Note that all getters on #GUdevDevice are non-reffing – returned
+ * values are owned by the object, should not be freed and are only
+ * valid as long as the object is alive.
+ *
+ * By design, #GUdevDevice will not react to changes for a device – it
+ * only contains a snapshot of information when the #GUdevDevice
+ * object was created. To work with changes, you typically connect to
+ * the #GUdevClient::uevent signal on a #GUdevClient and get a new
+ * #GUdevDevice whenever an event happens.
+ */
+
+struct _GUdevDevicePrivate
+{
+ struct udev_device *udevice;
+
+ /* computed ondemand and cached */
+ gchar **device_file_symlinks;
+ gchar **property_keys;
+ gchar **tags;
+ GHashTable *prop_strvs;
+ GHashTable *sysfs_attr_strvs;
+};
+
+G_DEFINE_TYPE (GUdevDevice, g_udev_device, G_TYPE_OBJECT)
+
+static void
+g_udev_device_finalize (GObject *object)
+{
+ GUdevDevice *device = G_UDEV_DEVICE (object);
+
+ g_strfreev (device->priv->device_file_symlinks);
+ g_strfreev (device->priv->property_keys);
+ g_strfreev (device->priv->tags);
+
+ if (device->priv->udevice != NULL)
+ udev_device_unref (device->priv->udevice);
+
+ if (device->priv->prop_strvs != NULL)
+ g_hash_table_unref (device->priv->prop_strvs);
+
+ if (device->priv->sysfs_attr_strvs != NULL)
+ g_hash_table_unref (device->priv->sysfs_attr_strvs);
+
+ if (G_OBJECT_CLASS (g_udev_device_parent_class)->finalize != NULL)
+ (* G_OBJECT_CLASS (g_udev_device_parent_class)->finalize) (object);
+}
+
+static void
+g_udev_device_class_init (GUdevDeviceClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+
+ gobject_class->finalize = g_udev_device_finalize;
+
+ g_type_class_add_private (klass, sizeof (GUdevDevicePrivate));
+}
+
+static void
+g_udev_device_init (GUdevDevice *device)
+{
+ device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
+ G_UDEV_TYPE_DEVICE,
+ GUdevDevicePrivate);
+}
+
+
+GUdevDevice *
+_g_udev_device_new (struct udev_device *udevice)
+{
+ GUdevDevice *device;
+
+ device = G_UDEV_DEVICE (g_object_new (G_UDEV_TYPE_DEVICE, NULL));
+ device->priv->udevice = udev_device_ref (udevice);
+
+ return device;
+}
+
+/**
+ * g_udev_device_get_subsystem:
+ * @device: A #GUdevDevice.
+ *
+ * Gets the subsystem for @device.
+ *
+ * Returns: The subsystem for @device.
+ */
+const gchar *
+g_udev_device_get_subsystem (GUdevDevice *device)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ return udev_device_get_subsystem (device->priv->udevice);
+}
+
+/**
+ * g_udev_device_get_devtype:
+ * @device: A #GUdevDevice.
+ *
+ * Gets the device type for @device.
+ *
+ * Returns: The devtype for @device.
+ */
+const gchar *
+g_udev_device_get_devtype (GUdevDevice *device)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ return udev_device_get_devtype (device->priv->udevice);
+}
+
+/**
+ * g_udev_device_get_name:
+ * @device: A #GUdevDevice.
+ *
+ * Gets the name of @device, e.g. "sda3".
+ *
+ * Returns: The name of @device.
+ */
+const gchar *
+g_udev_device_get_name (GUdevDevice *device)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ return udev_device_get_sysname (device->priv->udevice);
+}
+
+/**
+ * g_udev_device_get_number:
+ * @device: A #GUdevDevice.
+ *
+ * Gets the number of @device, e.g. "3" if g_udev_device_get_name() returns "sda3".
+ *
+ * Returns: The number of @device.
+ */
+const gchar *
+g_udev_device_get_number (GUdevDevice *device)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ return udev_device_get_sysnum (device->priv->udevice);
+}
+
+/**
+ * g_udev_device_get_sysfs_path:
+ * @device: A #GUdevDevice.
+ *
+ * Gets the sysfs path for @device.
+ *
+ * Returns: The sysfs path for @device.
+ */
+const gchar *
+g_udev_device_get_sysfs_path (GUdevDevice *device)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ return udev_device_get_syspath (device->priv->udevice);
+}
+
+/**
+ * g_udev_device_get_driver:
+ * @device: A #GUdevDevice.
+ *
+ * Gets the name of the driver used for @device.
+ *
+ * Returns: The name of the driver for @device or %NULL if unknown.
+ */
+const gchar *
+g_udev_device_get_driver (GUdevDevice *device)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ return udev_device_get_driver (device->priv->udevice);
+}
+
+/**
+ * g_udev_device_get_action:
+ * @device: A #GUdevDevice.
+ *
+ * Gets the most recent action (e.g. "add", "remove", "change", etc.) for @device.
+ *
+ * Returns: An action string.
+ */
+const gchar *
+g_udev_device_get_action (GUdevDevice *device)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ return udev_device_get_action (device->priv->udevice);
+}
+
+/**
+ * g_udev_device_get_seqnum:
+ * @device: A #GUdevDevice.
+ *
+ * Gets the most recent sequence number for @device.
+ *
+ * Returns: A sequence number.
+ */
+guint64
+g_udev_device_get_seqnum (GUdevDevice *device)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
+ return udev_device_get_seqnum (device->priv->udevice);
+}
+
+/**
+ * g_udev_device_get_device_type:
+ * @device: A #GUdevDevice.
+ *
+ * Gets the type of the device file, if any, for @device.
+ *
+ * Returns: The device number for @device or #G_UDEV_DEVICE_TYPE_NONE if the device does not have a device file.
+ */
+GUdevDeviceType
+g_udev_device_get_device_type (GUdevDevice *device)
+{
+ struct stat stat_buf;
+ const gchar *device_file;
+ GUdevDeviceType type;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), G_UDEV_DEVICE_TYPE_NONE);
+
+ type = G_UDEV_DEVICE_TYPE_NONE;
+
+ /* TODO: would be better to have support for this in libudev... */
+
+ device_file = g_udev_device_get_device_file (device);
+ if (device_file == NULL)
+ goto out;
+
+ if (stat (device_file, &stat_buf) != 0)
+ goto out;
+
+ if (S_ISBLK (stat_buf.st_mode))
+ type = G_UDEV_DEVICE_TYPE_BLOCK;
+ else if (S_ISCHR (stat_buf.st_mode))
+ type = G_UDEV_DEVICE_TYPE_CHAR;
+
+ out:
+ return type;
+}
+
+/**
+ * g_udev_device_get_device_number:
+ * @device: A #GUdevDevice.
+ *
+ * Gets the device number, if any, for @device.
+ *
+ * Returns: The device number for @device or 0 if unknown.
+ */
+GUdevDeviceNumber
+g_udev_device_get_device_number (GUdevDevice *device)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
+ return udev_device_get_devnum (device->priv->udevice);
+}
+
+/**
+ * g_udev_device_get_device_file:
+ * @device: A #GUdevDevice.
+ *
+ * Gets the device file for @device.
+ *
+ * Returns: The device file for @device or %NULL if no device file
+ * exists.
+ */
+const gchar *
+g_udev_device_get_device_file (GUdevDevice *device)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ return udev_device_get_devnode (device->priv->udevice);
+}
+
+/**
+ * g_udev_device_get_device_file_symlinks:
+ * @device: A #GUdevDevice.
+ *
+ * Gets a list of symlinks (in <literal>/dev</literal>) that points to
+ * the device file for @device.
+ *
+ * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of symlinks. This array is owned by @device and should not be freed by the caller.
+ */
+const gchar * const *
+g_udev_device_get_device_file_symlinks (GUdevDevice *device)
+{
+ struct udev_list_entry *l;
+ GPtrArray *p;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+
+ if (device->priv->device_file_symlinks != NULL)
+ goto out;
+
+ p = g_ptr_array_new ();
+ for (l = udev_device_get_devlinks_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
+ {
+ g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
+ }
+ g_ptr_array_add (p, NULL);
+ device->priv->device_file_symlinks = (gchar **) g_ptr_array_free (p, FALSE);
+
+ out:
+ return (const gchar * const *) device->priv->device_file_symlinks;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_udev_device_get_parent:
+ * @device: A #GUdevDevice.
+ *
+ * Gets the immediate parent of @device, if any.
+ *
+ * Returns: (transfer full): A #GUdevDevice or %NULL if @device has no parent. Free with g_object_unref().
+ */
+GUdevDevice *
+g_udev_device_get_parent (GUdevDevice *device)
+{
+ GUdevDevice *ret;
+ struct udev_device *udevice;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+
+ ret = NULL;
+
+ udevice = udev_device_get_parent (device->priv->udevice);
+ if (udevice == NULL)
+ goto out;
+
+ ret = _g_udev_device_new (udevice);
+
+ out:
+ return ret;
+}
+
+/**
+ * g_udev_device_get_parent_with_subsystem:
+ * @device: A #GUdevDevice.
+ * @subsystem: The subsystem of the parent to get.
+ * @devtype: (allow-none): The devtype of the parent to get or %NULL.
+ *
+ * Walks up the chain of parents of @device and returns the first
+ * device encountered where @subsystem and @devtype matches, if any.
+ *
+ * Returns: (transfer full): A #GUdevDevice or %NULL if @device has no parent with @subsystem and @devtype. Free with g_object_unref().
+ */
+GUdevDevice *
+g_udev_device_get_parent_with_subsystem (GUdevDevice *device,
+ const gchar *subsystem,
+ const gchar *devtype)
+{
+ GUdevDevice *ret;
+ struct udev_device *udevice;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (subsystem != NULL, NULL);
+
+ ret = NULL;
+
+ udevice = udev_device_get_parent_with_subsystem_devtype (device->priv->udevice,
+ subsystem,
+ devtype);
+ if (udevice == NULL)
+ goto out;
+
+ ret = _g_udev_device_new (udevice);
+
+ out:
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_udev_device_get_property_keys:
+ * @device: A #GUdevDevice.
+ *
+ * Gets all keys for properties on @device.
+ *
+ * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of property keys. This array is owned by @device and should not be freed by the caller.
+ */
+const gchar* const *
+g_udev_device_get_property_keys (GUdevDevice *device)
+{
+ struct udev_list_entry *l;
+ GPtrArray *p;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+
+ if (device->priv->property_keys != NULL)
+ goto out;
+
+ p = g_ptr_array_new ();
+ for (l = udev_device_get_properties_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
+ {
+ g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
+ }
+ g_ptr_array_add (p, NULL);
+ device->priv->property_keys = (gchar **) g_ptr_array_free (p, FALSE);
+
+ out:
+ return (const gchar * const *) device->priv->property_keys;
+}
+
+
+/**
+ * g_udev_device_has_property:
+ * @device: A #GUdevDevice.
+ * @key: Name of property.
+ *
+ * Check if a the property with the given key exists.
+ *
+ * Returns: %TRUE only if the value for @key exist.
+ */
+gboolean
+g_udev_device_has_property (GUdevDevice *device,
+ const gchar *key)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+ return udev_device_get_property_value (device->priv->udevice, key) != NULL;
+}
+
+/**
+ * g_udev_device_get_property:
+ * @device: A #GUdevDevice.
+ * @key: Name of property.
+ *
+ * Look up the value for @key on @device.
+ *
+ * Returns: The value for @key or %NULL if @key doesn't exist on @device. Do not free this string, it is owned by @device.
+ */
+const gchar *
+g_udev_device_get_property (GUdevDevice *device,
+ const gchar *key)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+ return udev_device_get_property_value (device->priv->udevice, key);
+}
+
+/**
+ * g_udev_device_get_property_as_int:
+ * @device: A #GUdevDevice.
+ * @key: Name of property.
+ *
+ * Look up the value for @key on @device and convert it to an integer
+ * using strtol().
+ *
+ * Returns: The value for @key or 0 if @key doesn't exist or
+ * isn't an integer.
+ */
+gint
+g_udev_device_get_property_as_int (GUdevDevice *device,
+ const gchar *key)
+{
+ gint result;
+ const gchar *s;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
+ g_return_val_if_fail (key != NULL, 0);
+
+ result = 0;
+ s = g_udev_device_get_property (device, key);
+ if (s == NULL)
+ goto out;
+
+ result = strtol (s, NULL, 0);
+out:
+ return result;
+}
+
+/**
+ * g_udev_device_get_property_as_uint64:
+ * @device: A #GUdevDevice.
+ * @key: Name of property.
+ *
+ * Look up the value for @key on @device and convert it to an unsigned
+ * 64-bit integer using g_ascii_strtoull().
+ *
+ * Returns: The value for @key or 0 if @key doesn't exist or isn't a
+ * #guint64.
+ */
+guint64
+g_udev_device_get_property_as_uint64 (GUdevDevice *device,
+ const gchar *key)
+{
+ guint64 result;
+ const gchar *s;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
+ g_return_val_if_fail (key != NULL, 0);
+
+ result = 0;
+ s = g_udev_device_get_property (device, key);
+ if (s == NULL)
+ goto out;
+
+ result = g_ascii_strtoull (s, NULL, 0);
+out:
+ return result;
+}
+
+/**
+ * g_udev_device_get_property_as_double:
+ * @device: A #GUdevDevice.
+ * @key: Name of property.
+ *
+ * Look up the value for @key on @device and convert it to a double
+ * precision floating point number using strtod().
+ *
+ * Returns: The value for @key or 0.0 if @key doesn't exist or isn't a
+ * #gdouble.
+ */
+gdouble
+g_udev_device_get_property_as_double (GUdevDevice *device,
+ const gchar *key)
+{
+ gdouble result;
+ const gchar *s;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0);
+ g_return_val_if_fail (key != NULL, 0.0);
+
+ result = 0.0;
+ s = g_udev_device_get_property (device, key);
+ if (s == NULL)
+ goto out;
+
+ result = strtod (s, NULL);
+out:
+ return result;
+}
+
+/**
+ * g_udev_device_get_property_as_boolean:
+ * @device: A #GUdevDevice.
+ * @key: Name of property.
+ *
+ * Look up the value for @key on @device and convert it to an
+ * boolean. This is done by doing a case-insensitive string comparison
+ * on the string value against "1" and "true".
+ *
+ * Returns: The value for @key or %FALSE if @key doesn't exist or
+ * isn't a #gboolean.
+ */
+gboolean
+g_udev_device_get_property_as_boolean (GUdevDevice *device,
+ const gchar *key)
+{
+ gboolean result;
+ const gchar *s;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ result = FALSE;
+ s = g_udev_device_get_property (device, key);
+ if (s == NULL)
+ goto out;
+
+ if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0)
+ result = TRUE;
+ out:
+ return result;
+}
+
+static gchar **
+split_at_whitespace (const gchar *s)
+{
+ gchar **result;
+ guint n;
+ guint m;
+
+ result = g_strsplit_set (s, " \v\t\r\n", 0);
+
+ /* remove empty strings, thanks GLib */
+ for (n = 0; result[n] != NULL; n++)
+ {
+ if (strlen (result[n]) == 0)
+ {
+ g_free (result[n]);
+ for (m = n; result[m] != NULL; m++)
+ result[m] = result[m + 1];
+ n--;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * g_udev_device_get_property_as_strv:
+ * @device: A #GUdevDevice.
+ * @key: Name of property.
+ *
+ * Look up the value for @key on @device and return the result of
+ * splitting it into non-empty tokens split at white space (only space
+ * (' '), form-feed ('\f'), newline ('\n'), carriage return ('\r'),
+ * horizontal tab ('\t'), and vertical tab ('\v') are considered; the
+ * locale is not taken into account).
+ *
+ * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): The value of @key on @device split into tokens or %NULL if @key doesn't exist. This array is owned by @device and should not be freed by the caller.
+ */
+const gchar* const *
+g_udev_device_get_property_as_strv (GUdevDevice *device,
+ const gchar *key)
+{
+ gchar **result;
+ const gchar *s;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+
+ if (device->priv->prop_strvs != NULL)
+ {
+ result = g_hash_table_lookup (device->priv->prop_strvs, key);
+ if (result != NULL)
+ goto out;
+ }
+
+ result = NULL;
+ s = g_udev_device_get_property (device, key);
+ if (s == NULL)
+ goto out;
+
+ result = split_at_whitespace (s);
+ if (result == NULL)
+ goto out;
+
+ if (device->priv->prop_strvs == NULL)
+ device->priv->prop_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev);
+ g_hash_table_insert (device->priv->prop_strvs, g_strdup (key), result);
+
+out:
+ return (const gchar* const *) result;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_udev_device_get_sysfs_attr:
+ * @device: A #GUdevDevice.
+ * @name: Name of the sysfs attribute.
+ *
+ * Look up the sysfs attribute with @name on @device.
+ *
+ * Returns: The value of the sysfs attribute or %NULL if there is no
+ * such attribute. Do not free this string, it is owned by @device.
+ */
+const gchar *
+g_udev_device_get_sysfs_attr (GUdevDevice *device,
+ const gchar *name)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+ return udev_device_get_sysattr_value (device->priv->udevice, name);
+}
+
+/**
+ * g_udev_device_get_sysfs_attr_as_int:
+ * @device: A #GUdevDevice.
+ * @name: Name of the sysfs attribute.
+ *
+ * Look up the sysfs attribute with @name on @device and convert it to an integer
+ * using strtol().
+ *
+ * Returns: The value of the sysfs attribute or 0 if there is no such
+ * attribute.
+ */
+gint
+g_udev_device_get_sysfs_attr_as_int (GUdevDevice *device,
+ const gchar *name)
+{
+ gint result;
+ const gchar *s;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
+ g_return_val_if_fail (name != NULL, 0);
+
+ result = 0;
+ s = g_udev_device_get_sysfs_attr (device, name);
+ if (s == NULL)
+ goto out;
+
+ result = strtol (s, NULL, 0);
+out:
+ return result;
+}
+
+/**
+ * g_udev_device_get_sysfs_attr_as_uint64:
+ * @device: A #GUdevDevice.
+ * @name: Name of the sysfs attribute.
+ *
+ * Look up the sysfs attribute with @name on @device and convert it to an unsigned
+ * 64-bit integer using g_ascii_strtoull().
+ *
+ * Returns: The value of the sysfs attribute or 0 if there is no such
+ * attribute.
+ */
+guint64
+g_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice *device,
+ const gchar *name)
+{
+ guint64 result;
+ const gchar *s;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
+ g_return_val_if_fail (name != NULL, 0);
+
+ result = 0;
+ s = g_udev_device_get_sysfs_attr (device, name);
+ if (s == NULL)
+ goto out;
+
+ result = g_ascii_strtoull (s, NULL, 0);
+out:
+ return result;
+}
+
+/**
+ * g_udev_device_get_sysfs_attr_as_double:
+ * @device: A #GUdevDevice.
+ * @name: Name of the sysfs attribute.
+ *
+ * Look up the sysfs attribute with @name on @device and convert it to a double
+ * precision floating point number using strtod().
+ *
+ * Returns: The value of the sysfs attribute or 0.0 if there is no such
+ * attribute.
+ */
+gdouble
+g_udev_device_get_sysfs_attr_as_double (GUdevDevice *device,
+ const gchar *name)
+{
+ gdouble result;
+ const gchar *s;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0);
+ g_return_val_if_fail (name != NULL, 0.0);
+
+ result = 0.0;
+ s = g_udev_device_get_sysfs_attr (device, name);
+ if (s == NULL)
+ goto out;
+
+ result = strtod (s, NULL);
+out:
+ return result;
+}
+
+/**
+ * g_udev_device_get_sysfs_attr_as_boolean:
+ * @device: A #GUdevDevice.
+ * @name: Name of the sysfs attribute.
+ *
+ * Look up the sysfs attribute with @name on @device and convert it to an
+ * boolean. This is done by doing a case-insensitive string comparison
+ * on the string value against "1" and "true".
+ *
+ * Returns: The value of the sysfs attribute or %FALSE if there is no such
+ * attribute.
+ */
+gboolean
+g_udev_device_get_sysfs_attr_as_boolean (GUdevDevice *device,
+ const gchar *name)
+{
+ gboolean result;
+ const gchar *s;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ result = FALSE;
+ s = g_udev_device_get_sysfs_attr (device, name);
+ if (s == NULL)
+ goto out;
+
+ if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0)
+ result = TRUE;
+ out:
+ return result;
+}
+
+/**
+ * g_udev_device_get_sysfs_attr_as_strv:
+ * @device: A #GUdevDevice.
+ * @name: Name of the sysfs attribute.
+ *
+ * Look up the sysfs attribute with @name on @device and return the result of
+ * splitting it into non-empty tokens split at white space (only space (' '),
+ * form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal
+ * tab ('\t'), and vertical tab ('\v') are considered; the locale is
+ * not taken into account).
+ *
+ * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): The value of the sysfs attribute split into tokens or %NULL if there is no such attribute. This array is owned by @device and should not be freed by the caller.
+ */
+const gchar * const *
+g_udev_device_get_sysfs_attr_as_strv (GUdevDevice *device,
+ const gchar *name)
+{
+ gchar **result;
+ const gchar *s;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ if (device->priv->sysfs_attr_strvs != NULL)
+ {
+ result = g_hash_table_lookup (device->priv->sysfs_attr_strvs, name);
+ if (result != NULL)
+ goto out;
+ }
+
+ result = NULL;
+ s = g_udev_device_get_sysfs_attr (device, name);
+ if (s == NULL)
+ goto out;
+
+ result = split_at_whitespace (s);
+ if (result == NULL)
+ goto out;
+
+ if (device->priv->sysfs_attr_strvs == NULL)
+ device->priv->sysfs_attr_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev);
+ g_hash_table_insert (device->priv->sysfs_attr_strvs, g_strdup (name), result);
+
+out:
+ return (const gchar* const *) result;
+}
+
+/**
+ * g_udev_device_get_tags:
+ * @device: A #GUdevDevice.
+ *
+ * Gets all tags for @device.
+ *
+ * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of tags. This array is owned by @device and should not be freed by the caller.
+ *
+ * Since: 165
+ */
+const gchar* const *
+g_udev_device_get_tags (GUdevDevice *device)
+{
+ struct udev_list_entry *l;
+ GPtrArray *p;
+
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+
+ if (device->priv->tags != NULL)
+ goto out;
+
+ p = g_ptr_array_new ();
+ for (l = udev_device_get_tags_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
+ {
+ g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
+ }
+ g_ptr_array_add (p, NULL);
+ device->priv->tags = (gchar **) g_ptr_array_free (p, FALSE);
+
+ out:
+ return (const gchar * const *) device->priv->tags;
+}
+
+/**
+ * g_udev_device_get_is_initialized:
+ * @device: A #GUdevDevice.
+ *
+ * Gets whether @device has been initalized.
+ *
+ * Returns: Whether @device has been initialized.
+ *
+ * Since: 165
+ */
+gboolean
+g_udev_device_get_is_initialized (GUdevDevice *device)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
+ return udev_device_get_is_initialized (device->priv->udevice);
+}
+
+/**
+ * g_udev_device_get_usec_since_initialized:
+ * @device: A #GUdevDevice.
+ *
+ * Gets number of micro-seconds since @device was initialized.
+ *
+ * This only works for devices with properties in the udev
+ * database. All other devices return 0.
+ *
+ * Returns: Number of micro-seconds since @device was initialized or 0 if unknown.
+ *
+ * Since: 165
+ */
+guint64
+g_udev_device_get_usec_since_initialized (GUdevDevice *device)
+{
+ g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
+ return udev_device_get_usec_since_initialized (device->priv->udevice);
+}
diff --git a/src/gudev/gudevdevice.h b/src/gudev/gudevdevice.h
new file mode 100644
index 0000000000..d4873bad0f
--- /dev/null
+++ b/src/gudev/gudevdevice.h
@@ -0,0 +1,128 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
+#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __G_UDEV_DEVICE_H__
+#define __G_UDEV_DEVICE_H__
+
+#include <gudev/gudevtypes.h>
+
+G_BEGIN_DECLS
+
+#define G_UDEV_TYPE_DEVICE (g_udev_device_get_type ())
+#define G_UDEV_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_DEVICE, GUdevDevice))
+#define G_UDEV_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_DEVICE, GUdevDeviceClass))
+#define G_UDEV_IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_DEVICE))
+#define G_UDEV_IS_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_DEVICE))
+#define G_UDEV_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_DEVICE, GUdevDeviceClass))
+
+typedef struct _GUdevDeviceClass GUdevDeviceClass;
+typedef struct _GUdevDevicePrivate GUdevDevicePrivate;
+
+/**
+ * GUdevDevice:
+ *
+ * The #GUdevDevice struct is opaque and should not be accessed directly.
+ */
+struct _GUdevDevice
+{
+ GObject parent;
+
+ /*< private >*/
+ GUdevDevicePrivate *priv;
+};
+
+/**
+ * GUdevDeviceClass:
+ * @parent_class: Parent class.
+ *
+ * Class structure for #GUdevDevice.
+ */
+struct _GUdevDeviceClass
+{
+ GObjectClass parent_class;
+
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*reserved1) (void);
+ void (*reserved2) (void);
+ void (*reserved3) (void);
+ void (*reserved4) (void);
+ void (*reserved5) (void);
+ void (*reserved6) (void);
+ void (*reserved7) (void);
+ void (*reserved8) (void);
+};
+
+GType g_udev_device_get_type (void) G_GNUC_CONST;
+gboolean g_udev_device_get_is_initialized (GUdevDevice *device);
+guint64 g_udev_device_get_usec_since_initialized (GUdevDevice *device);
+const gchar *g_udev_device_get_subsystem (GUdevDevice *device);
+const gchar *g_udev_device_get_devtype (GUdevDevice *device);
+const gchar *g_udev_device_get_name (GUdevDevice *device);
+const gchar *g_udev_device_get_number (GUdevDevice *device);
+const gchar *g_udev_device_get_sysfs_path (GUdevDevice *device);
+const gchar *g_udev_device_get_driver (GUdevDevice *device);
+const gchar *g_udev_device_get_action (GUdevDevice *device);
+guint64 g_udev_device_get_seqnum (GUdevDevice *device);
+GUdevDeviceType g_udev_device_get_device_type (GUdevDevice *device);
+GUdevDeviceNumber g_udev_device_get_device_number (GUdevDevice *device);
+const gchar *g_udev_device_get_device_file (GUdevDevice *device);
+const gchar* const *g_udev_device_get_device_file_symlinks (GUdevDevice *device);
+GUdevDevice *g_udev_device_get_parent (GUdevDevice *device);
+GUdevDevice *g_udev_device_get_parent_with_subsystem (GUdevDevice *device,
+ const gchar *subsystem,
+ const gchar *devtype);
+const gchar* const *g_udev_device_get_property_keys (GUdevDevice *device);
+gboolean g_udev_device_has_property (GUdevDevice *device,
+ const gchar *key);
+const gchar *g_udev_device_get_property (GUdevDevice *device,
+ const gchar *key);
+gint g_udev_device_get_property_as_int (GUdevDevice *device,
+ const gchar *key);
+guint64 g_udev_device_get_property_as_uint64 (GUdevDevice *device,
+ const gchar *key);
+gdouble g_udev_device_get_property_as_double (GUdevDevice *device,
+ const gchar *key);
+gboolean g_udev_device_get_property_as_boolean (GUdevDevice *device,
+ const gchar *key);
+const gchar* const *g_udev_device_get_property_as_strv (GUdevDevice *device,
+ const gchar *key);
+
+const gchar *g_udev_device_get_sysfs_attr (GUdevDevice *device,
+ const gchar *name);
+gint g_udev_device_get_sysfs_attr_as_int (GUdevDevice *device,
+ const gchar *name);
+guint64 g_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice *device,
+ const gchar *name);
+gdouble g_udev_device_get_sysfs_attr_as_double (GUdevDevice *device,
+ const gchar *name);
+gboolean g_udev_device_get_sysfs_attr_as_boolean (GUdevDevice *device,
+ const gchar *name);
+const gchar* const *g_udev_device_get_sysfs_attr_as_strv (GUdevDevice *device,
+ const gchar *name);
+const gchar* const *g_udev_device_get_tags (GUdevDevice *device);
+
+G_END_DECLS
+
+#endif /* __G_UDEV_DEVICE_H__ */
diff --git a/src/gudev/gudevenumerator.c b/src/gudev/gudevenumerator.c
new file mode 100644
index 0000000000..db09074625
--- /dev/null
+++ b/src/gudev/gudevenumerator.c
@@ -0,0 +1,431 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gudevclient.h"
+#include "gudevenumerator.h"
+#include "gudevdevice.h"
+#include "gudevmarshal.h"
+#include "gudevprivate.h"
+
+/**
+ * SECTION:gudevenumerator
+ * @short_description: Lookup and sort devices
+ *
+ * #GUdevEnumerator is used to lookup and sort devices.
+ *
+ * Since: 165
+ */
+
+struct _GUdevEnumeratorPrivate
+{
+ GUdevClient *client;
+ struct udev_enumerate *e;
+};
+
+enum
+{
+ PROP_0,
+ PROP_CLIENT,
+};
+
+G_DEFINE_TYPE (GUdevEnumerator, g_udev_enumerator, G_TYPE_OBJECT)
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+g_udev_enumerator_finalize (GObject *object)
+{
+ GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object);
+
+ if (enumerator->priv->client != NULL)
+ {
+ g_object_unref (enumerator->priv->client);
+ enumerator->priv->client = NULL;
+ }
+
+ if (enumerator->priv->e != NULL)
+ {
+ udev_enumerate_unref (enumerator->priv->e);
+ enumerator->priv->e = NULL;
+ }
+
+ if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize (object);
+}
+
+static void
+g_udev_enumerator_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_CLIENT:
+ if (enumerator->priv->client != NULL)
+ g_object_unref (enumerator->priv->client);
+ enumerator->priv->client = g_value_dup_object (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_udev_enumerator_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_CLIENT:
+ g_value_set_object (value, enumerator->priv->client);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_udev_enumerator_constructed (GObject *object)
+{
+ GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object);
+
+ g_assert (G_UDEV_IS_CLIENT (enumerator->priv->client));
+
+ enumerator->priv->e = udev_enumerate_new (_g_udev_client_get_udev (enumerator->priv->client));
+
+ if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed (object);
+}
+
+static void
+g_udev_enumerator_class_init (GUdevEnumeratorClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+
+ gobject_class->finalize = g_udev_enumerator_finalize;
+ gobject_class->set_property = g_udev_enumerator_set_property;
+ gobject_class->get_property = g_udev_enumerator_get_property;
+ gobject_class->constructed = g_udev_enumerator_constructed;
+
+ /**
+ * GUdevEnumerator:client:
+ *
+ * The #GUdevClient to enumerate devices from.
+ *
+ * Since: 165
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_CLIENT,
+ g_param_spec_object ("client",
+ "The client to enumerate devices from",
+ "The client to enumerate devices from",
+ G_UDEV_TYPE_CLIENT,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private (klass, sizeof (GUdevEnumeratorPrivate));
+}
+
+static void
+g_udev_enumerator_init (GUdevEnumerator *enumerator)
+{
+ enumerator->priv = G_TYPE_INSTANCE_GET_PRIVATE (enumerator,
+ G_UDEV_TYPE_ENUMERATOR,
+ GUdevEnumeratorPrivate);
+}
+
+/**
+ * g_udev_enumerator_new:
+ * @client: A #GUdevClient to enumerate devices from.
+ *
+ * Constructs a #GUdevEnumerator object that can be used to enumerate
+ * and sort devices. Use the add_match_*() and add_nomatch_*() methods
+ * and execute the query to get a list of devices with
+ * g_udev_enumerator_execute().
+ *
+ * Returns: A new #GUdevEnumerator object. Free with g_object_unref().
+ *
+ * Since: 165
+ */
+GUdevEnumerator *
+g_udev_enumerator_new (GUdevClient *client)
+{
+ g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
+ return G_UDEV_ENUMERATOR (g_object_new (G_UDEV_TYPE_ENUMERATOR, "client", client, NULL));
+}
+
+
+/**
+ * g_udev_enumerator_add_match_subsystem:
+ * @enumerator: A #GUdevEnumerator.
+ * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'.
+ *
+ * All returned devices will match the given @subsystem.
+ *
+ * Returns: (transfer none): The passed in @enumerator.
+ *
+ * Since: 165
+ */
+GUdevEnumerator *
+g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator,
+ const gchar *subsystem)
+{
+ g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
+ g_return_val_if_fail (subsystem != NULL, NULL);
+ udev_enumerate_add_match_subsystem (enumerator->priv->e, subsystem);
+ return enumerator;
+}
+
+/**
+ * g_udev_enumerator_add_nomatch_subsystem:
+ * @enumerator: A #GUdevEnumerator.
+ * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'.
+ *
+ * All returned devices will not match the given @subsystem.
+ *
+ * Returns: (transfer none): The passed in @enumerator.
+ *
+ * Since: 165
+ */
+GUdevEnumerator *
+g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator,
+ const gchar *subsystem)
+{
+ g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
+ g_return_val_if_fail (subsystem != NULL, NULL);
+ udev_enumerate_add_nomatch_subsystem (enumerator->priv->e, subsystem);
+ return enumerator;
+}
+
+/**
+ * g_udev_enumerator_add_match_sysfs_attr:
+ * @enumerator: A #GUdevEnumerator.
+ * @name: Wildcard filter for sysfs attribute key.
+ * @value: Wildcard filter for sysfs attribute value.
+ *
+ * All returned devices will have a sysfs attribute matching the given @name and @value.
+ *
+ * Returns: (transfer none): The passed in @enumerator.
+ *
+ * Since: 165
+ */
+GUdevEnumerator *
+g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator,
+ const gchar *name,
+ const gchar *value)
+{
+ g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (value != NULL, NULL);
+ udev_enumerate_add_match_sysattr (enumerator->priv->e, name, value);
+ return enumerator;
+}
+
+/**
+ * g_udev_enumerator_add_nomatch_sysfs_attr:
+ * @enumerator: A #GUdevEnumerator.
+ * @name: Wildcard filter for sysfs attribute key.
+ * @value: Wildcard filter for sysfs attribute value.
+ *
+ * All returned devices will not have a sysfs attribute matching the given @name and @value.
+ *
+ * Returns: (transfer none): The passed in @enumerator.
+ *
+ * Since: 165
+ */
+GUdevEnumerator *
+g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator,
+ const gchar *name,
+ const gchar *value)
+{
+ g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (value != NULL, NULL);
+ udev_enumerate_add_nomatch_sysattr (enumerator->priv->e, name, value);
+ return enumerator;
+}
+
+/**
+ * g_udev_enumerator_add_match_property:
+ * @enumerator: A #GUdevEnumerator.
+ * @name: Wildcard filter for property name.
+ * @value: Wildcard filter for property value.
+ *
+ * All returned devices will have a property matching the given @name and @value.
+ *
+ * Returns: (transfer none): The passed in @enumerator.
+ *
+ * Since: 165
+ */
+GUdevEnumerator *
+g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator,
+ const gchar *name,
+ const gchar *value)
+{
+ g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (value != NULL, NULL);
+ udev_enumerate_add_match_property (enumerator->priv->e, name, value);
+ return enumerator;
+}
+
+/**
+ * g_udev_enumerator_add_match_name:
+ * @enumerator: A #GUdevEnumerator.
+ * @name: Wildcard filter for kernel name e.g. "sda*".
+ *
+ * All returned devices will match the given @name.
+ *
+ * Returns: (transfer none): The passed in @enumerator.
+ *
+ * Since: 165
+ */
+GUdevEnumerator *
+g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator,
+ const gchar *name)
+{
+ g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+ udev_enumerate_add_match_sysname (enumerator->priv->e, name);
+ return enumerator;
+}
+
+/**
+ * g_udev_enumerator_add_sysfs_path:
+ * @enumerator: A #GUdevEnumerator.
+ * @sysfs_path: A sysfs path, e.g. "/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda"
+ *
+ * Add a device to the list of devices, to retrieve it back sorted in dependency order.
+ *
+ * Returns: (transfer none): The passed in @enumerator.
+ *
+ * Since: 165
+ */
+GUdevEnumerator *
+g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator,
+ const gchar *sysfs_path)
+{
+ g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
+ g_return_val_if_fail (sysfs_path != NULL, NULL);
+ udev_enumerate_add_syspath (enumerator->priv->e, sysfs_path);
+ return enumerator;
+}
+
+/**
+ * g_udev_enumerator_add_match_tag:
+ * @enumerator: A #GUdevEnumerator.
+ * @tag: A udev tag e.g. "udev-acl".
+ *
+ * All returned devices will match the given @tag.
+ *
+ * Returns: (transfer none): The passed in @enumerator.
+ *
+ * Since: 165
+ */
+GUdevEnumerator *
+g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator,
+ const gchar *tag)
+{
+ g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
+ g_return_val_if_fail (tag != NULL, NULL);
+ udev_enumerate_add_match_tag (enumerator->priv->e, tag);
+ return enumerator;
+}
+
+/**
+ * g_udev_enumerator_add_match_is_initialized:
+ * @enumerator: A #GUdevEnumerator.
+ *
+ * All returned devices will be initialized.
+ *
+ * Returns: (transfer none): The passed in @enumerator.
+ *
+ * Since: 165
+ */
+GUdevEnumerator *
+g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator)
+{
+ g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
+ udev_enumerate_add_match_is_initialized (enumerator->priv->e);
+ return enumerator;
+}
+
+/**
+ * g_udev_enumerator_execute:
+ * @enumerator: A #GUdevEnumerator.
+ *
+ * Executes the query in @enumerator.
+ *
+ * Returns: (element-type GUdevDevice) (transfer full): A list of #GUdevDevice objects. The caller should free the result by using g_object_unref() on each element in the list and then g_list_free() on the list.
+ *
+ * Since: 165
+ */
+GList *
+g_udev_enumerator_execute (GUdevEnumerator *enumerator)
+{
+ GList *ret;
+ struct udev_list_entry *l, *devices;
+
+ g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
+
+ ret = NULL;
+
+ /* retrieve the list */
+ udev_enumerate_scan_devices (enumerator->priv->e);
+
+ devices = udev_enumerate_get_list_entry (enumerator->priv->e);
+ for (l = devices; l != NULL; l = udev_list_entry_get_next (l))
+ {
+ struct udev_device *udevice;
+ GUdevDevice *device;
+
+ udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerator->priv->e),
+ udev_list_entry_get_name (l));
+ if (udevice == NULL)
+ continue;
+
+ device = _g_udev_device_new (udevice);
+ udev_device_unref (udevice);
+ ret = g_list_prepend (ret, device);
+ }
+
+ ret = g_list_reverse (ret);
+
+ return ret;
+}
diff --git a/src/gudev/gudevenumerator.h b/src/gudev/gudevenumerator.h
new file mode 100644
index 0000000000..3fddccf573
--- /dev/null
+++ b/src/gudev/gudevenumerator.h
@@ -0,0 +1,107 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
+#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __G_UDEV_ENUMERATOR_H__
+#define __G_UDEV_ENUMERATOR_H__
+
+#include <gudev/gudevtypes.h>
+
+G_BEGIN_DECLS
+
+#define G_UDEV_TYPE_ENUMERATOR (g_udev_enumerator_get_type ())
+#define G_UDEV_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_ENUMERATOR, GUdevEnumerator))
+#define G_UDEV_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_ENUMERATOR, GUdevEnumeratorClass))
+#define G_UDEV_IS_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_ENUMERATOR))
+#define G_UDEV_IS_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_ENUMERATOR))
+#define G_UDEV_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_ENUMERATOR, GUdevEnumeratorClass))
+
+typedef struct _GUdevEnumeratorClass GUdevEnumeratorClass;
+typedef struct _GUdevEnumeratorPrivate GUdevEnumeratorPrivate;
+
+/**
+ * GUdevEnumerator:
+ *
+ * The #GUdevEnumerator struct is opaque and should not be accessed directly.
+ *
+ * Since: 165
+ */
+struct _GUdevEnumerator
+{
+ GObject parent;
+
+ /*< private >*/
+ GUdevEnumeratorPrivate *priv;
+};
+
+/**
+ * GUdevEnumeratorClass:
+ * @parent_class: Parent class.
+ *
+ * Class structure for #GUdevEnumerator.
+ *
+ * Since: 165
+ */
+struct _GUdevEnumeratorClass
+{
+ GObjectClass parent_class;
+
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*reserved1) (void);
+ void (*reserved2) (void);
+ void (*reserved3) (void);
+ void (*reserved4) (void);
+ void (*reserved5) (void);
+ void (*reserved6) (void);
+ void (*reserved7) (void);
+ void (*reserved8) (void);
+};
+
+GType g_udev_enumerator_get_type (void) G_GNUC_CONST;
+GUdevEnumerator *g_udev_enumerator_new (GUdevClient *client);
+GUdevEnumerator *g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator,
+ const gchar *subsystem);
+GUdevEnumerator *g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator,
+ const gchar *subsystem);
+GUdevEnumerator *g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator,
+ const gchar *name,
+ const gchar *value);
+GUdevEnumerator *g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator,
+ const gchar *name,
+ const gchar *value);
+GUdevEnumerator *g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator,
+ const gchar *name,
+ const gchar *value);
+GUdevEnumerator *g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator,
+ const gchar *name);
+GUdevEnumerator *g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator,
+ const gchar *tag);
+GUdevEnumerator *g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator);
+GUdevEnumerator *g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator,
+ const gchar *sysfs_path);
+GList *g_udev_enumerator_execute (GUdevEnumerator *enumerator);
+
+G_END_DECLS
+
+#endif /* __G_UDEV_ENUMERATOR_H__ */
diff --git a/src/gudev/gudevenums.h b/src/gudev/gudevenums.h
new file mode 100644
index 0000000000..c3a0aa8747
--- /dev/null
+++ b/src/gudev/gudevenums.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
+#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __G_UDEV_ENUMS_H__
+#define __G_UDEV_ENUMS_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GUdevDeviceType:
+ * @G_UDEV_DEVICE_TYPE_NONE: Device does not have a device file.
+ * @G_UDEV_DEVICE_TYPE_BLOCK: Device is a block device.
+ * @G_UDEV_DEVICE_TYPE_CHAR: Device is a character device.
+ *
+ * Enumeration used to specify a the type of a device.
+ */
+typedef enum
+{
+ G_UDEV_DEVICE_TYPE_NONE = 0,
+ G_UDEV_DEVICE_TYPE_BLOCK = 'b',
+ G_UDEV_DEVICE_TYPE_CHAR = 'c',
+} GUdevDeviceType;
+
+G_END_DECLS
+
+#endif /* __G_UDEV_ENUMS_H__ */
diff --git a/src/gudev/gudevenumtypes.c.template b/src/gudev/gudevenumtypes.c.template
new file mode 100644
index 0000000000..fc30b39e2e
--- /dev/null
+++ b/src/gudev/gudevenumtypes.c.template
@@ -0,0 +1,39 @@
+/*** BEGIN file-header ***/
+#include <gudev.h>
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+@enum_name@_get_type (void)
+{
+ static volatile gsize g_define_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_define_type_id__volatile))
+ {
+ static const G@Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+ GType g_define_type_id =
+ g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
+ g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+ }
+
+ return g_define_type_id__volatile;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+/*** END file-tail ***/
diff --git a/src/gudev/gudevenumtypes.h.template b/src/gudev/gudevenumtypes.h.template
new file mode 100644
index 0000000000..d0ab3393e6
--- /dev/null
+++ b/src/gudev/gudevenumtypes.h.template
@@ -0,0 +1,24 @@
+/*** BEGIN file-header ***/
+#ifndef __GUDEV_ENUM_TYPES_H__
+#define __GUDEV_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type (void) G_GNUC_CONST;
+#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* __GUDEV_ENUM_TYPES_H__ */
+/*** END file-tail ***/
diff --git a/src/gudev/gudevmarshal.list b/src/gudev/gudevmarshal.list
new file mode 100644
index 0000000000..7e665999e8
--- /dev/null
+++ b/src/gudev/gudevmarshal.list
@@ -0,0 +1 @@
+VOID:STRING,OBJECT
diff --git a/src/gudev/gudevprivate.h b/src/gudev/gudevprivate.h
new file mode 100644
index 0000000000..8866f52b88
--- /dev/null
+++ b/src/gudev/gudevprivate.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
+#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __G_UDEV_PRIVATE_H__
+#define __G_UDEV_PRIVATE_H__
+
+#include <gudev/gudevtypes.h>
+
+#include <libudev.h>
+
+G_BEGIN_DECLS
+
+GUdevDevice *
+_g_udev_device_new (struct udev_device *udevice);
+
+struct udev *_g_udev_client_get_udev (GUdevClient *client);
+
+G_END_DECLS
+
+#endif /* __G_UDEV_PRIVATE_H__ */
diff --git a/src/gudev/gudevtypes.h b/src/gudev/gudevtypes.h
new file mode 100644
index 0000000000..888482783d
--- /dev/null
+++ b/src/gudev/gudevtypes.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
+#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __G_UDEV_TYPES_H__
+#define __G_UDEV_TYPES_H__
+
+#include <gudev/gudevenums.h>
+#include <sys/types.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GUdevClient GUdevClient;
+typedef struct _GUdevDevice GUdevDevice;
+typedef struct _GUdevEnumerator GUdevEnumerator;
+
+/**
+ * GUdevDeviceNumber:
+ *
+ * Corresponds to the standard #dev_t type as defined by POSIX (Until
+ * bug 584517 is resolved this work-around is needed).
+ */
+#ifdef _GUDEV_WORK_AROUND_DEV_T_BUG
+typedef guint64 GUdevDeviceNumber; /* __UQUAD_TYPE */
+#else
+typedef dev_t GUdevDeviceNumber;
+#endif
+
+G_END_DECLS
+
+#endif /* __G_UDEV_TYPES_H__ */
diff --git a/src/gudev/seed-example-enum.js b/src/gudev/seed-example-enum.js
new file mode 100755
index 0000000000..66206ad806
--- /dev/null
+++ b/src/gudev/seed-example-enum.js
@@ -0,0 +1,38 @@
+#!/usr/bin/env seed
+
+const GLib = imports.gi.GLib;
+const GUdev = imports.gi.GUdev;
+
+function print_device(device) {
+ print(" initialized: " + device.get_is_initialized());
+ print(" usec since initialized: " + device.get_usec_since_initialized());
+ print(" subsystem: " + device.get_subsystem());
+ print(" devtype: " + device.get_devtype());
+ print(" name: " + device.get_name());
+ print(" number: " + device.get_number());
+ print(" sysfs_path: " + device.get_sysfs_path());
+ print(" driver: " + device.get_driver());
+ print(" action: " + device.get_action());
+ print(" seqnum: " + device.get_seqnum());
+ print(" device type: " + device.get_device_type());
+ print(" device number: " + device.get_device_number());
+ print(" device file: " + device.get_device_file());
+ print(" device file symlinks: " + device.get_device_file_symlinks());
+ print(" tags: " + device.get_tags());
+ var keys = device.get_property_keys();
+ for (var n = 0; n < keys.length; n++) {
+ print(" " + keys[n] + "=" + device.get_property(keys[n]));
+ }
+}
+
+var client = new GUdev.Client({subsystems: []});
+var enumerator = new GUdev.Enumerator({client: client});
+enumerator.add_match_subsystem('b*')
+
+var devices = enumerator.execute();
+
+for (var n=0; n < devices.length; n++) {
+ var device = devices[n];
+ print_device(device);
+ print("");
+}
diff --git a/src/gudev/seed-example.js b/src/gudev/seed-example.js
new file mode 100755
index 0000000000..e2ac324d23
--- /dev/null
+++ b/src/gudev/seed-example.js
@@ -0,0 +1,72 @@
+#!/usr/bin/env seed
+
+// seed example
+
+const GLib = imports.gi.GLib;
+const GUdev = imports.gi.GUdev;
+
+function print_device (device) {
+ print (" subsystem: " + device.get_subsystem ());
+ print (" devtype: " + device.get_devtype ());
+ print (" name: " + device.get_name ());
+ print (" number: " + device.get_number ());
+ print (" sysfs_path: " + device.get_sysfs_path ());
+ print (" driver: " + device.get_driver ());
+ print (" action: " + device.get_action ());
+ print (" seqnum: " + device.get_seqnum ());
+ print (" device type: " + device.get_device_type ());
+ print (" device number: " + device.get_device_number ());
+ print (" device file: " + device.get_device_file ());
+ print (" device file symlinks: " + device.get_device_file_symlinks ());
+ print (" foo: " + device.get_sysfs_attr_as_strv ("stat"));
+ var keys = device.get_property_keys ();
+ for (var n = 0; n < keys.length; n++) {
+ print (" " + keys[n] + "=" + device.get_property (keys[n]));
+ }
+}
+
+function on_uevent (client, action, device) {
+ print ("action " + action + " on device " + device.get_sysfs_path());
+ print_device (device);
+ print ("");
+}
+
+var client = new GUdev.Client ({subsystems: ["block", "usb/usb_interface"]});
+client.signal.connect ("uevent", on_uevent);
+
+var block_devices = client.query_by_subsystem ("block");
+for (var n = 0; n < block_devices.length; n++) {
+ print ("block device: " + block_devices[n].get_device_file ());
+}
+
+var d;
+
+d = client.query_by_device_number (GUdev.DeviceType.BLOCK, 0x0810);
+if (d == null) {
+ print ("query_by_device_number 0x810 -> null");
+} else {
+ print ("query_by_device_number 0x810 -> " + d.get_device_file ());
+ dd = d.get_parent_with_subsystem ("usb", null);
+ print_device (dd);
+ print ("--------------------------------------------------------------------------");
+ while (d != null) {
+ print_device (d);
+ print ("");
+ d = d.get_parent ();
+ }
+}
+
+d = client.query_by_sysfs_path ("/sys/block/sda/sda1");
+print ("query_by_sysfs_path (\"/sys/block/sda1\") -> " + d.get_device_file ());
+
+d = client.query_by_subsystem_and_name ("block", "sda2");
+print ("query_by_subsystem_and_name (\"block\", \"sda2\") -> " + d.get_device_file ());
+
+d = client.query_by_device_file ("/dev/sda");
+print ("query_by_device_file (\"/dev/sda\") -> " + d.get_device_file ());
+
+d = client.query_by_device_file ("/dev/block/8:0");
+print ("query_by_device_file (\"/dev/block/8:0\") -> " + d.get_device_file ());
+
+var mainloop = GLib.main_loop_new ();
+GLib.main_loop_run (mainloop);