1 /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
3 * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "gudevclient.h"
28 #include "gudevdevice.h"
29 #include "gudevmarshal.h"
30 #include "gudevprivate.h"
34 * @short_description: Query devices and listen to uevents
36 * #GUdevClient is used to query information about devices on a Linux
37 * system from the Linux kernel and the udev device
40 * Device information is retrieved from the kernel (through the
41 * <literal>sysfs</literal> filesystem) and the udev daemon (through a
42 * <literal>tmpfs</literal> filesystem) and presented through
43 * #GUdevDevice objects. This means that no blocking IO ever happens
44 * (in both cases, we are essentially just reading data from kernel
45 * memory) and as such there are no asynchronous versions of the
48 * To get #GUdevDevice objects, use
49 * g_udev_client_query_by_subsystem(),
50 * g_udev_client_query_by_device_number(),
51 * g_udev_client_query_by_device_file(),
52 * g_udev_client_query_by_sysfs_path(),
53 * g_udev_client_query_by_subsystem_and_name()
54 * or the #GUdevEnumerator type.
56 * To listen to uevents, connect to the #GUdevClient::uevent signal.
59 struct _GUdevClientPrivate
61 GSource *watch_source;
63 struct udev_monitor *monitor;
80 static guint signals[LAST_SIGNAL] = { 0 };
82 G_DEFINE_TYPE (GUdevClient, g_udev_client, G_TYPE_OBJECT)
84 /* ---------------------------------------------------------------------------------------------------- */
87 monitor_event (GIOChannel *source,
88 GIOCondition condition,
91 GUdevClient *client = (GUdevClient *) data;
93 struct udev_device *udevice;
95 if (client->priv->monitor == NULL)
97 udevice = udev_monitor_receive_device (client->priv->monitor);
101 device = _g_udev_device_new (udevice);
102 udev_device_unref (udevice);
103 g_signal_emit (client,
104 signals[UEVENT_SIGNAL],
106 g_udev_device_get_action (device),
108 g_object_unref (device);
115 g_udev_client_finalize (GObject *object)
117 GUdevClient *client = G_UDEV_CLIENT (object);
119 if (client->priv->watch_source != NULL)
121 g_source_destroy (client->priv->watch_source);
122 client->priv->watch_source = NULL;
125 if (client->priv->monitor != NULL)
127 udev_monitor_unref (client->priv->monitor);
128 client->priv->monitor = NULL;
131 if (client->priv->udev != NULL)
133 udev_unref (client->priv->udev);
134 client->priv->udev = NULL;
137 g_strfreev (client->priv->subsystems);
139 if (G_OBJECT_CLASS (g_udev_client_parent_class)->finalize != NULL)
140 G_OBJECT_CLASS (g_udev_client_parent_class)->finalize (object);
144 g_udev_client_set_property (GObject *object,
149 GUdevClient *client = G_UDEV_CLIENT (object);
153 case PROP_SUBSYSTEMS:
154 if (client->priv->subsystems != NULL)
155 g_strfreev (client->priv->subsystems);
156 client->priv->subsystems = g_strdupv (g_value_get_boxed (value));
160 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
166 g_udev_client_get_property (GObject *object,
171 GUdevClient *client = G_UDEV_CLIENT (object);
175 case PROP_SUBSYSTEMS:
176 g_value_set_boxed (value, client->priv->subsystems);
180 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
186 g_udev_client_constructed (GObject *object)
188 GUdevClient *client = G_UDEV_CLIENT (object);
192 client->priv->udev = udev_new ();
194 /* connect to event source */
195 client->priv->monitor = udev_monitor_new_from_netlink (client->priv->udev, "udev");
197 //g_debug ("ss = %p", client->priv->subsystems);
199 if (client->priv->subsystems != NULL)
201 /* install subsystem filters to only wake up for certain events */
202 for (n = 0; client->priv->subsystems[n] != NULL; n++)
208 subsystem = g_strdup (client->priv->subsystems[n]);
211 //g_debug ("s = '%s'", subsystem);
213 s = strstr (subsystem, "/");
220 if (client->priv->monitor != NULL)
221 udev_monitor_filter_add_match_subsystem_devtype (client->priv->monitor, subsystem, devtype);
226 /* listen to events, and buffer them */
227 if (client->priv->monitor != NULL)
229 udev_monitor_enable_receiving (client->priv->monitor);
230 channel = g_io_channel_unix_new (udev_monitor_get_fd (client->priv->monitor));
231 client->priv->watch_source = g_io_create_watch (channel, G_IO_IN);
232 g_io_channel_unref (channel);
233 g_source_set_callback (client->priv->watch_source, (GSourceFunc) monitor_event, client, NULL);
234 g_source_attach (client->priv->watch_source, g_main_context_get_thread_default ());
235 g_source_unref (client->priv->watch_source);
239 client->priv->watch_source = NULL;
243 if (G_OBJECT_CLASS (g_udev_client_parent_class)->constructed != NULL)
244 G_OBJECT_CLASS (g_udev_client_parent_class)->constructed (object);
249 g_udev_client_class_init (GUdevClientClass *klass)
251 GObjectClass *gobject_class = (GObjectClass *) klass;
253 gobject_class->constructed = g_udev_client_constructed;
254 gobject_class->set_property = g_udev_client_set_property;
255 gobject_class->get_property = g_udev_client_get_property;
256 gobject_class->finalize = g_udev_client_finalize;
259 * GUdevClient:subsystems:
261 * The subsystems to listen for uevents on.
263 * To listen for only a specific DEVTYPE for a given SUBSYSTEM, use
264 * "subsystem/devtype". For example, to only listen for uevents
265 * where SUBSYSTEM is usb and DEVTYPE is usb_interface, use
266 * "usb/usb_interface".
268 * If this property is %NULL, then no events will be reported. If
269 * it's the empty array, events from all subsystems will be
272 g_object_class_install_property (gobject_class,
274 g_param_spec_boxed ("subsystems",
275 "The subsystems to listen for changes on",
276 "The subsystems to listen for changes on",
278 G_PARAM_CONSTRUCT_ONLY |
282 * GUdevClient::uevent:
283 * @client: The #GUdevClient receiving the event.
284 * @action: The action for the uevent e.g. "add", "remove", "change", "move", etc.
285 * @device: Details about the #GUdevDevice the event is for.
287 * Emitted when @client receives an uevent.
289 * This signal is emitted in the
290 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
291 * of the thread that @client was created in.
293 signals[UEVENT_SIGNAL] = g_signal_new ("uevent",
294 G_TYPE_FROM_CLASS (klass),
296 G_STRUCT_OFFSET (GUdevClientClass, uevent),
299 g_udev_marshal_VOID__STRING_OBJECT,
305 g_type_class_add_private (klass, sizeof (GUdevClientPrivate));
309 g_udev_client_init (GUdevClient *client)
311 client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client,
318 * @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.
320 * Constructs a #GUdevClient object that can be used to query
321 * information about devices. Connect to the #GUdevClient::uevent
322 * signal to listen for uevents. Note that signals are emitted in the
323 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
324 * of the thread that you call this constructor from.
326 * Returns: A new #GUdevClient object. Free with g_object_unref().
329 g_udev_client_new (const gchar * const *subsystems)
331 return G_UDEV_CLIENT (g_object_new (G_UDEV_TYPE_CLIENT, "subsystems", subsystems, NULL));
335 * g_udev_client_query_by_subsystem:
336 * @client: A #GUdevClient.
337 * @subsystem: (allow-none): The subsystem to get devices for or %NULL to get all devices.
339 * Gets all devices belonging to @subsystem.
341 * 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.
344 g_udev_client_query_by_subsystem (GUdevClient *client,
345 const gchar *subsystem)
347 struct udev_enumerate *enumerate;
348 struct udev_list_entry *l, *devices;
351 g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
355 /* prepare a device scan */
356 enumerate = udev_enumerate_new (client->priv->udev);
358 /* filter for subsystem */
359 if (subsystem != NULL)
360 udev_enumerate_add_match_subsystem (enumerate, subsystem);
361 /* retrieve the list */
362 udev_enumerate_scan_devices (enumerate);
364 /* add devices to the list */
365 devices = udev_enumerate_get_list_entry (enumerate);
366 for (l = devices; l != NULL; l = udev_list_entry_get_next (l))
368 struct udev_device *udevice;
371 udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate),
372 udev_list_entry_get_name (l));
375 device = _g_udev_device_new (udevice);
376 udev_device_unref (udevice);
377 ret = g_list_prepend (ret, device);
379 udev_enumerate_unref (enumerate);
381 ret = g_list_reverse (ret);
387 * g_udev_client_query_by_device_number:
388 * @client: A #GUdevClient.
389 * @type: A value from the #GUdevDeviceType enumeration.
390 * @number: A device number.
392 * Looks up a device for a type and device number.
394 * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref().
397 g_udev_client_query_by_device_number (GUdevClient *client,
398 GUdevDeviceType type,
399 GUdevDeviceNumber number)
401 struct udev_device *udevice;
404 g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
407 udevice = udev_device_new_from_devnum (client->priv->udev, type, number);
412 device = _g_udev_device_new (udevice);
413 udev_device_unref (udevice);
420 * g_udev_client_query_by_device_file:
421 * @client: A #GUdevClient.
422 * @device_file: A device file.
424 * Looks up a device for a device file.
426 * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref().
429 g_udev_client_query_by_device_file (GUdevClient *client,
430 const gchar *device_file)
432 struct stat stat_buf;
435 g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
436 g_return_val_if_fail (device_file != NULL, NULL);
440 if (stat (device_file, &stat_buf) != 0)
443 if (stat_buf.st_rdev == 0)
446 if (S_ISBLK (stat_buf.st_mode))
447 device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_BLOCK, stat_buf.st_rdev);
448 else if (S_ISCHR (stat_buf.st_mode))
449 device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_CHAR, stat_buf.st_rdev);
456 * g_udev_client_query_by_sysfs_path:
457 * @client: A #GUdevClient.
458 * @sysfs_path: A sysfs path.
460 * Looks up a device for a sysfs path.
462 * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref().
465 g_udev_client_query_by_sysfs_path (GUdevClient *client,
466 const gchar *sysfs_path)
468 struct udev_device *udevice;
471 g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
472 g_return_val_if_fail (sysfs_path != NULL, NULL);
475 udevice = udev_device_new_from_syspath (client->priv->udev, sysfs_path);
479 device = _g_udev_device_new (udevice);
480 udev_device_unref (udevice);
487 * g_udev_client_query_by_subsystem_and_name:
488 * @client: A #GUdevClient.
489 * @subsystem: A subsystem name.
490 * @name: The name of the device.
492 * Looks up a device for a subsystem and name.
494 * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref().
497 g_udev_client_query_by_subsystem_and_name (GUdevClient *client,
498 const gchar *subsystem,
501 struct udev_device *udevice;
504 g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
505 g_return_val_if_fail (subsystem != NULL, NULL);
506 g_return_val_if_fail (name != NULL, NULL);
509 udevice = udev_device_new_from_subsystem_sysname (client->priv->udev, subsystem, name);
513 device = _g_udev_device_new (udevice);
514 udev_device_unref (udevice);
521 _g_udev_client_get_udev (GUdevClient *client)
523 g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
524 return client->priv->udev;